shell條件判斷 流程控制 與 迴圈語句
條件判斷
1、語法格式
1、test 條件表示式
2、[ 條件表示式 ] ***中括號兩邊得有空格 有空值得加雙引號否則會報錯,[]裡面不能加&& ||
3、[[ 條件表示式 ]] 支援正側 = ~ ***中括號兩邊得有空格 可以有空值 裡面可以用&& ||
2、常用判斷條件
為真則輸出0假則輸出1
-e #判斷檔案是否存在(任何型別檔案)(存在為真,不存在為假) [ -e ./app ];echo $? -f #判斷檔案是否存在並且是一個普通檔案 [ -f ./stu ];echo $? -d #判斷檔案是否存在並且是一個目錄 [ -d ./app ]; echo $? -L #判斷檔案是否存在並且是一個軟連線檔案 [ -L ./test ];echo $? -b #判斷檔案是否存在並且是一個裝置檔案-S(大寫S) #判斷檔案是否存在並且是一個套接字檔案
-s(小寫s) #判斷檔案是否有內容(非空為真)
! -s(小寫) #判斷檔案是否無內容(空檔案為真) -c #判斷檔案是否存在並且是一個字元裝置檔案 -p #判斷檔案是否存在並且是一個命名管道檔案
! #取反 用以以上條件的取反 檔案許可權相關判斷 -r #當前使用者對其是否可讀 [ -r ./frist_text.sh ];echo $? -w #當前使用者是否可寫 -x #當前使用者對其是否可執行 -u #是否有suid 高階許可權冒險位-g #是否sgid,高階許可權強制位 -k #是否有T位,高階許可權粘滯位 判斷檔案新舊: file1 -nt file2 #比較file1是否比file2新 test file1 -nt file2;echo $? file1 -ot file2 #比較file1是否比file2舊 test file1 -nt file2;echo $? file1 -ef file2 #比較是否為同一個檔案,或者用於判斷硬連線,是否指向同一個inode -eq #相等 [ 1 -eq 2 ];echo $? -ne #不等-gt #大於 -lt #小於 -ge #大於等於 -le #小於等於
字串的判斷:(=和==都表示判斷,但不等於只能用!=) -z 判斷是否為空字元,字串長度為0則成立 A=123 [ -z "" ];echo $? [ -z "$A"];echo $? (判斷變數A是否為空) -n 判斷是否為非空字串,字串長度不為0則成立 [ -z "aaa" ];echo $? [ string1 = string2 ] 判斷字串是否相等 (字串最好要用引號引起來,作為一個整體[]若有空字串且不加引號會報錯) [ string1 != string2 ]判斷字串是否不相等 [ "$A" != "$B" ];echo $? (判斷變數A和B 是否不相等)
#read -p "input yours name:" name
marry
[ "$name" = "marry" ] (變數name是否等於marry) 多重條件判斷 -a 和 && 邏輯與 (全真為真,有假就假) -o 和 || 邏輯或 (全假才假,有真必真) a&&b : a和b同時為true 才返回 true, 否則返回false; a || b :a或b任意一個為true 就返回true , 否則返回false
[ 1 -eq 1 -a 1 -ne 0 ] 整個表示式為真
[ 1 -eq 1 ]&&[ 1 -ne 0 ]
[[ 1 -eq 1 && 1 -ne 0 ]]
[ 1 -eq 1 -o 1 -ne 1 ] 第一個為真,第二個為假。整個表示式為真
[ 1 -eq 1 ]||[ 1 -ne 1 ]
[[ 1 -eq 1 || 1 -ne 1 ]]
總結:
1、; && ||都可以用來分割命令或表示式
2、;無論前面的語句是否錯誤,都會執行後邊的語句
3、&& 前面的語句正確,才會執行後邊的語句
4、|| 前面的語句錯誤,才會執行後邊的語句
5、如果&&與||一起出現,從左往右依次看,遵循上邊的規則
[ 1 -eq 1 ] && echo hello || echo world :第一個為真所以&&後的正確執行輸出 因為第二個正確執行為真所以||不執行
[ 1 -eq 2 ] && echo hello || echo world :第一個為假所以&&後的不執行 ||直接對第一個進行判斷為假 所以執行
[ 1 -eq 1 ] || echo hello && echo world :第一個為真所以||後的不執行 &&直接對第一個判斷為真 所以執行
[ 1 -eq 2 ] || echo hello && echo world :第一個為假所以||後的執行輸出 ||後的執行正確 為真 所以&&後的執行
類c風格的數值比較:(())中=表示賦值(只能賦予數值),==表示判斷 < 小於 >=大於等於 !=不等於
(( $(id -u)==0 )) &&echo is admin :id-u 表示uid使用者編號
流程控制語句
1、語法
F:files假
T:true真
1、
if [condition];then #[condition] 判斷語句:若為真則執行下面語句
command
fi
2、
if [condition1];then 若滿足條件一則執行command1結束
command 1
elif[condition2];then 若不滿足條件一,滿足條件二,則執行command2結束
command2
else 若12都不滿足,則執行commamd3結束
command3
fi
3、
if [condition1];then 若滿足條件一則執行command1
command 1
if [condition2];then 若滿足條件2則執行command2結束 不滿足2則結束
command2
if
else
if [condition3];then 若不滿足條件一滿足條件3,則執行command3結束
command3
elif[condition4];then 若不滿足條件一,滿足條件4,則執行command4結束
command4
else 若1 3 4都不滿足,則執行commamd5結束
command5
fi
fi
應用案例
需求一:判斷當前主機是否能夠和遠端主機ping通
#!/bin/bash
read -p "輸入遠端主機IP:" IP
ping -c1 $IP &>/tmp/file1 #把輸出的放入到file1檔案
if [ $? -eq 0 ];then
echo "ping通了"
else
echo "沒ping通"
fi
#!/bin/bash
if [ $# -ne 1 ];then
echo "沒有ip" && exit
fi
ping -c1 $1 &>/tmp/file1
[ $? -eq 0 ] && echo "ping通了" || echo "沒ping通"
或者
#!/bin/bash
if [ $# -ne 1 ];then
echo "沒有ip"
else
ping -c1 $1 &>/tmp/file1
[ $? -eq 0 ] && echo "ping通了" || echo "沒ping通"
fi
需求2 判斷程序是否存在
思路:
1.檢視程序的相關命令 ps -ef pgrep ps auxf pidof
2.根據命令的返回狀態值來判斷程序是否存在 $?
3.根據邏輯用指令碼語言實現
#!/bin/bash
# Name:process.sh
# Path:/shell02/
# Usage:/shell02/process.sh
# Describe:判斷一個程序是否存在
# 定義變數
read -p "請輸入需要判斷的程序名(httpd):" process
# 通過命令來檢視程序是否存在
pgrep $process &>/dev/null
# 通過命令執行的狀態來判斷是否存在
if [ $? -eq 0 ];then
echo "程序$process存在"
else
echo "程序$process不存在"
fi
或者
[ $? -eq 0 ] && echo "程序$process存在" || echo "程序$process不存在"
pgrep命令:以名稱為依據從執行程序佇列中查詢程序,並顯示查詢到的程序id
選項
-o:僅顯示找到的最小(起始)程序號;
-n:僅顯示找到的最大(結束)程序號;
-l:顯示程序名稱;
-P:指定父程序號;pgrep -p 4764 檢視父程序下的子程序id
-g:指定程序組;
-t:指定開啟程序的終端;
-u:指定程序的有效使用者ID。
-
可以判斷程序是否存在,用/etc/init.d/httpd status判斷狀態等方法
-
#!/bin/bash wget http://10.1.1.2 &>/dev/null [ $? -eq 0 ] && echo "該web服務是正常的" && rm -f /shell/shell01/index.* || echo "該web服務異常請檢查"
read -p "請輸入需要判斷的使用者名稱:" user id $user &>/dev/null test $? -eq 0 && echo "該$user存在" || echo "該$user不存在"
2、判斷vsftpd軟體包是否安裝,如果沒有則自動安裝(yum源已配好)
#!/bin/bash rpm -q vsftpd &> /dev/null #-q 查詢是否安裝 if [ $? -eq 0 ];then echo "vsftpd已經安裝" else echo "該軟體包沒有安裝,正在安裝...." yum install -y vsftpd &> /dev/null if [ $? -eq 0 ];then echo "vsftpd安裝成功" else echo "vsftpd安裝失敗" fi fi
3、判斷當前核心主版本是否為3,且次版本是否大於等於6;如果都滿足則輸出當前核心版本
思路: 1. 先檢視核心的版本號 uname -r 2. 先將核心的版本號儲存到一個變數裡,然後再根據需求截取出該變數的一部分:主版本和次版本 3. 根據需求進步判斷 #!/bin/bash kernel=`uname -r` # ``=$() var1=`echo $kernel|cut -d. -f1` var2=`echo $kernel|cut -d. -f2` test $var1 -eq 3 -a $var2 -ge 6 && echo $kernel || echo "當前核心版本不符合要求" # -a=&& 或者 [ $var1 -eq 3 -a $var2 -ge 6 ] && echo $kernel || echo "當前核心版本不符合要求" 或者 [[ $var1 -eq 3 && $var2 -ge 6 ]] && echo $kernel || echo "當前核心版本不符合要求"
#如果用下邊兩個得知道版本和次版本的位數
或者 #!/bin/bash
kernel=`uname -r`
test ${kernel:0:1} -eq 3 -a ${kernel:2:2} -ge 6 && echo $kernel || echo '不符合要求'
其他命令參考:
uname -r|grep ^3.[6-9] || echo '不符合要求' #次版本為單位數
vsftpd伺服器已啟動...
vsftpd監聽的埠是:
參考1: #!/bin/bash service vsftpd status &>/dev/null if [ $? -eq 0 ];then port=`netstat -tnltp|grep vsftpd|cut -d: -f2|cut -d' ' -f1` pid=`pgrep -l vsftpd|cut -d ' ' -f1` echo -e "vsftpd伺服器已啟動...\nvsftpd監聽的埠是:$port\nvsftpd的程序PID是:$pid" else service vsftpd start &>/dev/null port=`netstat -tnltp|grep vsftpd|cut -d: -f2|cut -d' ' -f1` pid=`pgrep -l vsftpd|cut -d ' ' -f1` echo -e "vsftpd伺服器已啟動...\nvsftpd監聽的埠是:$port\nvsftpd的程序PID是:$pid" fi 參考2: [root@server shell02]# cat liufeng.sh #!/bin/bash service $1 status if [ $? -eq 0 ];then echo " '$1'伺服器已啟動..." a=$( netstat -tnulp | grep $1 ) array=($a) echo "$1的監聽埠是:$(echo ${array[3]} | cut -d: -f2) " echo "$1的程序ID為:$(echo ${array[6]}| cut -d/ -f1)" else echo "$1程序未啟動!" fi 參考3: vim /lt/2.sh #! /bin/bash duankou=`netstat -ntlp|grep vsftpd|cut -d: -f2|cut -d" " -f1` pid=`pgrep -o vsftpd` vim 1.sh pgrep -l vsftpd >/dev/null if [ $? -eq 0 ];then echo "vsftpd伺服器已啟動..." echo "vsftpd監聽的埠是:$duankou" echo "vsftpd的程序PID是:$pid" else echo "vsftpd伺服器沒啟動" service vsftpd start source /lt/2.sh fi
1.1 語法結構
-
列表迴圈
列表for迴圈:用於將一組命令執行已知的次數
for variable in {list} do command command … done 或者 for variable in a b c do command command done
-n是換行
/n是不換行
語法結構舉例說明:
1045 for var in {1..10};do echo $var;done 1046 for var in 1 2 3 4 5;do echo $var;done 1047 for var in `seq 10`;do echo $var;done 1048 for var in $(seq 10);do echo $var;done 1049 for var in {0..10..2};do echo $var;done 1050 for var in {2..10..2};do echo $var;done 1051 for var in {10..1};do echo $var;done 1052 for var in {10..1..-2};do echo $var;done 1055 for var in `seq 10 -2 1`;do echo $var;done
{0..10..2}表示 從零開始列印,沒列印一次var加2一直到其大於10為止 停止列印 輸出 0,3,5,7,9
{10..1..-2} 表示 從10開始列印 沒列印一次var減2 一直到其小於1 停止列印 輸出 10,8,6,4,2
for var in {1..10..-2};do echo $var;done 也會輸出 1 ,3,5,7,9
seq命令的使用
作用:seq命令用於以指定增量從首數開始列印數字到尾數,即產生從某個數到另外一個數之間的所有整數,並且可以對整數的格式、寬度、分割符號進行控制
語法:
[1] seq [選項] 尾數
[2] seq [選項] 首數 尾數
[3] seq [選項] 首數 增量 尾數 (seq 起始值 步長 終止值)
選項:
-f, --format=格式 按照指定的格式輸出,不能和-f一起用(在不指定格式的情況下,預設格式為'%g')
-s, --separator=分隔符 指定輸出的分隔符,預設為\n,即預設為回車換行
-w, --sequal-width 指定為定寬輸出,不能和-w一起使用
製表符(\t)相當於 Tab 鍵
例項:
[1] 產生5以內的整數
命令:seq 5
輸出:
[2]產生-2~10內的整數,增量為2
命令:seq -2 2 10
輸出:
[3] 產生98~101之間的整數,並且要求輸出數字寬度相同,不足的用空格補足。
命令: seq -f "%3g" 98 101 ("%3g" 這種格式表示指定“位寬”為三位,數字位數不足部分用空格補位)
輸出:
命令:seq -f "%03g" 98 101 ("%03g" 這種格式表示指定“位寬”為三位,數字位數不足部分用0補位,通過%後新增0替代空格補足空位)
輸出:
注意:其實 % 前面還可以指定字串
列如:一次性建立5個名為dir001,dir002,..dir005的目錄
1、mkdir $(seq -f 'dir%03g' 1 5)
2、seq -f 'dir%03g' 1 5 | xargs mkdir
[4] 產生98~101之間的整數,並且要求數字之間的分隔符為":::"。
命令:seq -s ":::" -f "%03g" 98 101
輸出:
[5]輸出98~100之間的整數,要求寬度一致(-w 以最大值的位數為標準寬度,不足標準寬度的數字將會用0補位)
命令:seq -w 98 101
輸出:
注意:-w選項不能和-f選項一起用,輸出是同寬的
不帶列表的for迴圈執行時由使用者指定引數和引數的個數
for variable do command command … done
語法結構舉例說明:
#!/bin/bash for var do echo $var done echo "指令碼後面有$#個引數"
for(( expr1;expr2;expr3 )) do command command … done for (( i=1;i<=5;i++)) do echo $i done expr1:定義變數並賦初值 expr2:決定是否進行迴圈(條件) expr3:決定迴圈變數如何改變,決定迴圈什麼時候退出
語法結構舉例說明:
1068 for ((i=1;i<=5;i++));do echo $i;done 1069 for ((i=1;i<=10;i+=2));do echo $i;done 1070 for ((i=2;i<=10;i+=2));do echo $i;done
例1:思路:1. 定義一個變數來儲存奇數的和 sum=02. 找出1-100的奇數,儲存到另一個變數裡 i3. 從1-100中找出奇數後,再相加,然後將和賦值給sum變數4. 遍歷完畢後,將sum的值打印出#!/bin/bash#定義一個變數來儲存奇數的和
思路:
1. 定義一個變數來儲存奇數的和 sum=0
2. 找出1-100的奇數,儲存到另一個變數裡 i
3. 從1-100中找出奇數後,再相加,然後將和賦值給sum變數
4. 遍歷完畢後,將sum的值打印出來
延伸: true 真 : 真 false 假 方法1: #!/bin/bash sum=0 for i in {1..100..2} do sum=$[$i+$sum] done echo "1-100的奇數和為:$sum" 方法2: #!/bin/bash sum=0 for ((i=1;i<=100;i+=2)) do let sum=i+sum #let 命令是 BASH 中用於計算的工具,用於執行一個或多個表示式,變數計算中不需要加上 $ 來表示變數。如果表示式中包含了空格或其他特殊字元,則必須引起來。
#let sum=sum+$i
#let sum=sum+i
#let sum=$sum+$i
done
echo "1-100的奇數和為:$sum"
方法3: #!/bin/bash sum=0 for ((i=1;i<=100;i++)) do if [ $[$i%2] -ne 0 ];then #$[] $(()) :它們是一樣的,都是進行數學運算的。支援+ - * / %:分別為 “加、減、乘、除、取模”。但是注意,bash只能作整數運算,對於浮點數是當作字串處理的。
let sum=$sum+$i fi 或者 test $[$i%2] -ne 0 && let sum=$sum+$i done echo "1-100的奇數和為:$sum" 方法4: sum=0 for ((i=1;i<=100;i++)) do if [ $[$i%2] -eq 0 ];then continue else let sum=$sum+$i fi done echo "1-100的奇數和為:$sum" #!/bin/bash sum=0 for ((i=1;i<=100;i++)) do test $[$i%2] -eq 0 && continue || let sum=sum+$i #continue 代表繼續 也可以換成true 或: 代表0為真 done echo "1-100的奇數和是:$sum"
迴圈體: ==do....done==之間的內容
-
continue:繼續;表示==迴圈體==內下面的程式碼不執行,重新開始下一次迴圈
-
break:打斷;馬上停止執行本次迴圈,執行==迴圈體==後面的程式碼
-
[root@server ~]# cat for5.sh #!/bin/bash for i in {1..5} do test $i -eq 2 && break || touch /tmp/file$i done echo hello hahahah
思路: 0. 讓使用者輸入一個數,儲存到一個變數裡 read num 1、如果能被其他數整除就不是質數——>$num%$i 是否等於0 $i=2~$num-1 2、如果輸入的數是1或者2取模根據上面判斷又不符合,所以先排除1和2 3、測試序列從2開始,輸入的數是4——>得出結果$num不能和$i相等,並且$num不能小於$i
#!/bin/bash
read -p "請輸入一個正整數字:" number
[ $number -eq 1 ] && echo "$number不是質數" && exit
[ $number -eq 2 ] && echo "$number是質數" && exit
for i in `seq 2 $[$number-1]`
do
[ $[$number%$i] -eq 0 ] && echo "$number不是質數" && exit
done
echo "$number是質數" && exit
bash -x for6.sh
思路: 1. 新增使用者的命令 useradd -G 2. 判斷class組是否存在 grep -w class /etc/group;echo $? 3. 根據題意,判斷該指令碼迴圈5次來新增使用者 for迴圈 4. 給使用者設定密碼,應該放到迴圈體裡面 #!/bin/bash #判斷class組是否存在 grep -w class /etc/group &>/dev/null [ $? -ne 0 ] && groupadd class #批量建立5個使用者 for i in {1..5} do useradd -G class u$i echo 123|passwd --stdin u$i done #!/bin/bash #判斷class組是否存在 cut -d: -f1 /etc/group|grep -w class &>/dev/null [ $? -ne 0 ] && groupadd class #迴圈增加使用者,迴圈次數5次,for迴圈,給使用者設定密碼 for ((i=1;i<=5;i++)) do useradd u$i -G class echo 123|passwd --stdin u$i done #!/bin/bash grep -w class /etc/group &>/dev/null test $? -ne 0 && groupadd class 或者 groupadd class &>/dev/null for ((i=1;i<=5;i++)) do useradd -G class u$i && echo 123|passwd --stdin u$i done
#!/bin/bash #判斷/rhome是否存在 [ -f /rhome ] && mv /rhome /rhome.bak test ! -f /rhome -a ! -d /rhome && mkdir /rhome 或者 [ -f /rhome ] && mv /rhome /rhome.bak || [ ! -d /rhome ] && mkdir /rhome #建立使用者,迴圈5次 for ((i=1;i<=5;i++)) do useradd -d /rhome/stu$i stu$i echo 123|passwd --stdin stu$i done
#!/bin/bash #定義變數 ip=10.1.1 #迴圈去ping主機的IP for ((i=1;i<=10;i++)) do ping -c1 $ip.$i &>/dev/null if [ $? -eq 0 ];then echo "$ip.$i is ok" >> /tmp/ip_up.txt else echo "$ip.$i is down" >> /tmp/ip_down.txt fi 或者 [ $? -eq 0 ] && echo "$ip.$i is ok" >> /tmp/ip_up.txt || echo "$ip.$i is down" >> /tmp/ip_down.txt done [root@server shell03]# time ./ping.sh real 0m24.129s user 0m0.006s sys 0m0.005s 並行執行: {程式}&表示將程式放到後臺並行執行,如果需要等待程式執行完畢再進行下面內容,需要加wait #!/bin/bash #定義變數 ip=10.1.1 #迴圈去ping主機的IP for ((i=1;i<=10;i++)) do { ping -c1 $ip.$i &>/dev/null if [ $? -eq 0 ];then echo "$ip.$i is ok" >> /tmp/ip_up.txt else echo "$ip.$i is down" >> /tmp/ip_down.txt fi }& done wait echo "ip is ok...." [root@server ~]# time ./ping.sh ip is ok... real 0m3.091s user 0m0.001s sys 0m0.008s
3、輸入一個年份,判斷是否是潤年(能被4整除但不能被100整除,或能被400整除的年份即為閏年。)
#!/bin/bash read -p "Please input year:(2017)" year if [ $[$year%4] -eq 0 -a $[$year%100] -ne 0 ];then echo "$year is leap year" elif [ $[$year%400] -eq 0 ];then echo "$year is leap year" else echo "$year is not leap year" fi
特點:==條件為真就進入迴圈;條件為假就退出迴圈==
while 表示式 do command... done while [ 1 -eq 1 ] 或者 (( 1 > 2 )) do command command ... done ========================================================= 列印1-5數字 FOR迴圈列印: for ((i=1;i<=5;i++)) do echo $i done while迴圈列印: i=1 while [ $i -le 5 ] do echo $i let i++ done
#!/bin/bash #定義變數 sum=0 i=2 #迴圈列印1-50的偶數和並且計算後重新賦值給sum while [ $i -le 50 ] do let sum=sum+i let i+=2 done #列印sum的值 echo "1-50的偶數和為:$sum"
需求:
寫一個30秒同步一次時間,向同步伺服器10.1.1.250的指令碼,如果同步失敗,則進行郵件報警,每次失敗都報警;同步成功,也進行郵件通知,但是成功100次才通知一次。
分析:
-
每個30s同步一次時間,該指令碼是一個死迴圈
-
while true;do 同步時間,然後休息30s(sleep 30)done
-
-
同步失敗傳送郵件
-
在do.....done迴圈體之間加if...else...(判斷同步失敗還是成功)
-
-
同步成功100次傳送郵件
-
#!/bin/bash #定義變數 count=0 ntp_server=10.1.1.250 while true do rdate -s $ntp-server &>/dev/null if [ $? -ne 0 ];then echo "system date failed" |mail -s 'check system date' root@localhost else let count++ if [ $[$count%100] -eq 0 ];then echo "system date successfull" |mail -s 'check system date' root@localhost && count=0 fi fi sleep 3 done
3.1 語法結構
until expression [ 1 -eq 1 ] (( 1 >= 1 )) do command command ... done i=1 while [ $i -le 5 ] do echo $i let i++ done i=1 until [ $i -gt 5 ] do echo $i let i++ done
#!/bin/bash i=1 until [ $i -gt 10 ] do if [ $i -le 5 ];then useradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$i else [ ! -d /rhome ] && mkdir /rhome useradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i fi let i++ done