shell 編程
Shell 是一個命令行解釋器,它為用戶提供了一個向 Linux 內核發送請求以便運行程序的界面系統級程序,用戶可以用 Shell 來啟動、掛起、停止甚至是編寫一些程序。
shell 腳本的執行方式
-
腳本以#!/bin/bash 開頭
-
腳本需要有可執行權限
第一個 Shell 腳本
#!/bin/bash
echo "hello,world~"
腳本的常用執行方式
方式 1 (輸入腳本的絕對路徑或相對路徑)
說明:首先要賦予 helloworld.sh
腳本的 +x
權限, 再執行腳本
./hello.sh 或 /root/shcode/hello.sh
方式 2 ( sh + 腳本)
說明:不用賦予腳本+x 權限,直接執行即可。
sh hello.sh
Shell 的變量
- Linux Shell 中的變量分為,系統變量和用戶自定義變量。
- 系統變量:
$HOME
、$PWD
、$SHELL
、$USER
等等 - 顯示當前
shell
中所有變量:set
shell 變量的定義
基本語法
定義變量
變量名=值
撤銷變量
unset 變量
聲明靜態變量
readonly 變量
細節說明
- 變量名稱可以由字母、數字和下划線組成,但是不能以數字開頭
- 等號兩側不能有空格
- 靜態變量不能
unset
- 變量名稱一般習慣為大寫, 這是一個規范
將命令的返回值賦給變量
A=date
反引號,運行里面的命令,並把結果返回給變量 A
A=$(date)
等價於反引號
設置環境變量
基本語法
將 shell
變量輸出為環境變量/全局變量
export 變量名=變量值
讓修改后的配置信息立即生效
source 配置文件
查詢環境變量的值
echo $變量名
快速入門
- 在
/etc/profile
文件中定義TOMCAT_HOME
環境變量 - 查看環境變量
TOMCAT_HOME
的值 - 在另外一個
shell
程序中使用TOMCAT_HOME
注意:在輸出 TOMCAT_HOME
環境變量前,需要讓其生效
source /etc/profile
shell 腳本的多行注釋
:<<!
內容
!
位置參數變量
當執行一個 shell
腳本時,如果希望獲取到命令行的參數信息,就可以使用到位置參數變量
比如 : ./myshell.sh 100 200
, 這個就是一個執行 shell
的命令行,可以在 myshell
腳本中獲取到參數信息
基本語法
$n
:n 為數字,$0 代表命令本身,$1-$9 代表第一到第九個參數,十以上的參數,十以上的參數需要用大括號包含,如${10}
$*
:這個變量代表命令行中所有的參數,$*
把所有的參數看成一個整體
$@
:這個變量也代表命令行中所有的參數,不過$@把每個參數區分對待
$#
:這個變量代表命令行中所有參數的個數
實例演示
編寫一個 shell
腳本 position.sh
,在腳本中獲取到命令行的各個參數信息
#! /bin/bash
echo "0=$0 1=$1"
echo "參數=$*"
echo "$@"
echo "參數的個數=$#"
輸入:sh position.sh 100 200
預定義變量
就是 shell 設計者事先已經定義好的變量,可以直接在 shell 腳本中使用
基本語法
$$
:當前進程的進程號PID
$!
:后台運行的最后一個進程的進程號(PID)
$?
:最后一次執行的命令的返回狀態。如果這個變量的值為 0,證明上一個命令正確執行;如果這個變量的值為非 0(具體是哪個數,由命令自己來決定),則證明上一個命令執行不正確了。
#!/bin/bash
echo "當前執行的進程 id=$$"
#以后台的方式運行一個腳本,並獲取他的進程號
/root/shcode/myshell.sh &
echo "最后一個后台方式運行的進程 id=$!"
echo "執行的結果是=$?"
運算符
基本語法
$((運算式))
或
$[運算式]
或
expr m + n
細節說明
- 注意
expr
運算符間要有空格, 如果希望將expr
的結果賦給某個變量,使用 `` - expr *, /, % 乘,除,取余
應用實例
案例 1:計算(2+3)X4 的值
#! /bin/bash
#使用第一種方式
RES1=$(((2+3)*4))
echo "res1=$RES1"
#使用第二種方式, 推薦使用
RES2=$[(2+3)*4]
echo "res2=$RES2"
#使用第三種方式 expr
TEMP=`expr 2 + 3`
RES4=`expr $TEMP \* 4`
echo "temp=$TEMP"
echo "res4=$RES4"
條件判斷
判斷語句
基本語法
[ condition ]
細節說明
- 注意 condition 前后要有空格
- 非空返回 true,可使用$?驗證(0 為 true,>1 為 false)
應用實例
[ hspEdu ] 返回 true
[ ] 返回 false
[ condition ] && echo OK || echo notok 條件滿足,執行后面的語句
常用判斷條件
- 字符串比較
=
- 兩個整數的比較
-lt
小於
-le
小於等於 little equal
-eq
等於
-gt
大於
-ge
大於等於
-ne
不等於
流程控制
if 判斷
基本語法
if [ 條件判斷式 ]
then
代碼
fi
多分支
if [ 條件判斷式 ]
then
代碼
elif [條件判斷式]
then
代碼
fi
細節說明
- [ 條件判斷式 ],中括號和條件判斷式之間必須有空格
應用實例
編寫一個 shell 程序,如果輸入的參數,大於等於 60,則輸出 "及格了",如果小於 60,則輸出 "不及格"
#! /bin/bash
if [ $1 -ge 60 ]
then
echo "及格"
elif [ $1 -lt 60 ]
then
echo "不及格"
fi
case 語句
基本語法
case $變量名 in
"值 1")
如果變量的值等於值 1,則執行程序 1
;;
"值 2")
如果變量的值等於值 2,則執行程序 2
;;
…省略其他分支…
*)
如果變量的值都不是以上的值,則執行此程序
;;
esac
應用實例
當命令行參數是 1 時,輸出 "周一", 是 2 時,就輸出"周二", 其它情況輸出 "other"
#! /bin/bash
case $1 in
"1")
;;
echo "周一"
"2")
echo "周二"
;;
*)
echo "other..."
;;
esac
for 循環
基本語法
for 變量 in 值 1 值 2 值 3…
do
程序/代碼
done
for (( 初始值;循環控制條件;變量變化 ))
do
程序 /代碼
done
應用實例
- 打印命令行輸入的參數 [這里可以看出$* 和 $@ 的區別]
#! /bin/bash
#使用$*
for i in "$*"
do
echo "num is $i"
done
#使用$@
for i in "$@"
do
echo "num is $i"
done
- 從命令行輸入一個數 n,統計從 1+..+ n 的值是多少?
#! /bin/bash
SUM=0
for(( i=1; i<=$1; i++))
do
SUM=$[$SUM+$i]
done
echo "SUM=$SUM"
while 循環
基本語法
while [ 條件判斷式 ]
do
程序/代碼
done
細節說明
while
和[
有空格,條件判斷式和[
也有空格
應用實例
從命令行輸入一個數 n,統計從 1+..+ n 的值是多少?
#!/bin/bash
SUM=0
i=0
while [ $i -le $1 ]
do
SUM=$[$SUM+$i]
#i 自增
i=$[$i+1]
done
echo "執行結果=$SUM"
read 讀取控制台輸入
基本語法
read(選項)(參數)
選項說明
-p
:指定讀取值時的提示符
-t
:指定讀取值時等待的時間(秒),如果沒有在指定的時間內輸入,就不再等待
參數說明
- 變量:指定讀取值的變量名
應用實例
讀取控制台輸入一個 NUM2 值,在 10 秒內輸入
read -t 10 -p "請輸入一個數 NUM2=" NUM2
echo "你輸入的 NUM2=$NUM2"
函數
shell 編程和其它編程語言一樣,有系統函數,也可以自定義函數。
系統函數
basename
返回完整路徑最后 / 的部分,常用於獲取文件名
basename [pathname] [suffix]
basename [string] [suffix]
basename
命令會刪掉所有的前綴包括最后一個(‘/’)字符,然后將字符串顯示出來。
選項說明
- suffix 為后綴,如果 suffix 被指定了,basename 會將 pathname 或 string 中的 suffix 去掉。
dirname
返回完整路徑最后 / 的前面的部分,常用於返回路徑部分
dirname 文件絕對路徑
從給定的包含絕對路徑的文件名中
應用實例
請返回 /home/aaa/test.txt
的 /home/aaa
dirname /home/aaa/test.txt
自定義函數
基本語法
[ function ] funname[()]
{
Action;
[return int;]
}
調用直接寫函數名:funname [值]
應用實例
計算輸入兩個參數的和(動態的獲取), getSum
#!/bin/bash
#定義函數 getSum
function getSum() {
SUM=$[$n1+$n2]
echo "和是=$SUM"
}
#輸入兩個值
read -p "請輸入一個數 n1=" n1
read -p "請輸入一個數 n2=" n2
#調用自定義函數
getSum $n1 $n2
Shell 編程綜合案例
每天凌晨 2:30 備份 數據庫 hspedu 到 /data/backup/db
備份開始和備份結束能夠給出相應的提示信息
備份后的文件要求以備份時間為文件名,並打包成 .tar.gz 的形式,比如:2021-08-19_130201.tar.gz
在備份的同時,檢查是否有 10 天前備份的數據庫文件,如果有就將其刪除。
編寫 mysql_db_backup.sh
#備份目錄
BACKUP=/data/backup/db
#當前時間
DATETIME=$(date +%Y-%m-%d_%H%M%S)
echo $DATETIME
#數據庫的地址
HOST=localhost
#數據庫用戶名
DB_USER=root
#數據庫密碼
DB_PW=hspedu100
#備份的數據庫名
DATABASE=hspedu
#創建備份目錄, 如果不存在,就創建
[ ! -d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"
#備份數據庫
mysqldump -u${DB_USER} -p${DB_PW} --host=${HOST} -q -R --databases ${DATABASE} | gzip >
${BACKUP}/${DATETIME}/$DATETIME.sql.gz
#將文件處理成 tar.gz
cd ${BACKUP}
tar -zcvf $DATETIME.tar.gz ${DATETIME}
#刪除對應的備份目錄
rm -rf ${BACKUP}/${DATETIME}
#刪除 10 天前的備份文件
find ${BACKUP} -atime +10 -name "*.tar.gz" -exec rm -rf {} \;
echo "備份數據庫${DATABASE} 成功~"
設置定時任務,每天凌晨2:30執行
crontab -l
30 2 * * * /usr/sbin/mysql_db_backup.sh