shell的結構化命令
shell在邏輯流程控制這裡會根據設定的變數值的條件或其他命令的結果跳過一些命令或者迴圈執行的這些命令。這些命令通常稱為結構化命令
1、if-then語句介紹
基本格式 if command then commands fi 在其他語言中if語句後的物件值為TRUE或FALSE的等式、bash shell指令碼中的if不是這樣的 [root@eyu sbin]# sh data.sh 2018年 10月 04日 星期四 18:45:15 CST echo it worked [root@eyu sbin]# cat data.sh #!/bin/bash if date then echo echo "it worked" fi [root@eyu sbin]# sh data.sh data.sh:行2: data: 未找到命令 [root@eyu sbin]# cat data.sh #!/bin/bash if data ##修改後的 then echo echo "it worked" fi
bash shell中的if語句在if行定義的命令。如果命令的退出狀態是0(成功執行),將執行then後面的所有命令,如果命令的退出狀態是非0的,那麼then後面的命令將不會執行。
($?命令的返回狀態) 0 命令成功結束 1 通用未知錯誤 2 誤用shell命令 126 命令不可執行 127 沒找到命令 128 無效退出引數 128+x Linux 訊號x的嚴重錯誤 130 Linux 訊號2 的嚴重錯誤,即命令通過SIGINT(Ctrl+C)終止 255 退出狀態碼越界
另一種形式 if command;then conmmands fi
2、if-then-else語句
那麼相應的命名返回狀態為非0時,還需要執行一些需求時就需要多一種選擇
命令的結構式
if command ;then commands else commands fi
如果命令的返回狀態為非0時,bash shell會移步到指令碼的下一條命令。反之就會執行在then部分。
[root@eyu sbin]# cat grep1.sh grep.sh #!/bin/bash user=nihao ##判斷存在的使用者 if grep $user /etc/passwd;then echo the files for user $user are: else echo "the user name $user doesn't exist this system" fi #!/bin/bash user=root ##判斷存在的使用者 if grep $user /etc/passwd;then echo the files for user $user are: else echo "the user name $user doesn't exist this system" fi [root@eyu sbin]# [root@eyu sbin]# sh grep.sh root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin the files for user root are: [root@eyu sbin]# sh grep1.sh the user name nihao doesn't exist this system
3、巢狀if語句
有時在指令碼程式碼中需要檢查幾種情況。if-then-else滿足不了時,需要elif。
if command1;then commands elif command2;then commands elif command3;then commands fi
像這種情況會按循序匹配command1/2/3的執行返回值,第一個返回0時的elif會執行then部分
4、test命令
if語句中除了執行普通的shell命令外,還有一個test命令。
test命令根據退出程式碼狀態,判斷條件執行條件為true或者false。
test的命令格式: test condithon condition是一系列test命令評估的引數和值。在if-then語句中使用時,命令格式: if test condition;then commands fi 或 if [ condition ];then commands fi 方括號裡定義了test命令的使用條件。(在括號裡括號的開頭和結尾必須加一個空格,否則會報錯) test命令能夠評估一下3類條件: *數值比較 *字串比較 *檔案比較
4.1數值比較

數值比較.png
[root@eyu sbin]# sh contrast.sh 1 2 不相等 [root@eyu sbin]# sh contrast.sh 2 2 相等 [root@eyu sbin]# cat contrast.sh #!/bin/bash if [ $1 -eq $2 ];then echo 相等 else echo 不相等 fi [root@eyu sbin]# 依次類推
在test命令中是不能夠傳浮點數的,命令中會報錯
[root@eyu sbin]# sh folt.sh 3.333 folt.sh: 第 4 行:[: 3.333: 期待一元表示式 我們不一樣 [root@eyu sbin]# cat folt.sh #!/bin/bash a=`echo "scale=3;10/3" |bc` echo $a if [ $a >= 3 ];then echo 一樣 else echo 我們不一樣 fi
4.2字串比較

字串比較.png
等於判斷 [root@eyu sbin]# cat str.sh #!/bin/bash if [ $1 = $2 ];then echo 一樣 elif [ $1 != $2 ];then echo 不一樣 fi [root@eyu sbin]# sh str.sh aa aa 一樣 [root@eyu sbin]# sh str.sh aa bb 不一樣 字串比較長度是的大於或小於在shell中要特別注意倆點: *大於和小於一定要轉義,否則shell會解釋成重定向符號,將字串看出檔名 *大於和小於順序於在sort命令中的順序不同 [root@eyu sbin]# sh str.sh thccc 大於 [root@eyu sbin]# sh str.sh thcc 不大於 [root@eyu sbin]# cat str.sh #!/bin/bash a=thcc if [ $1 \> $a ];then echo 大於 else echo 不大於 fi [root@eyu sbin]# sh str.sh bb 大於 [root@eyu sbin]# sh str.sh bbaaa 大於 [root@eyu sbin]# sh str.sh bbaaaaaa 大於 [root@eyu sbin]# cat str.sh #!/bin/bash a=thcc if [ $1 > $a ];then ##要的結果變成了重定向 echo 大於 else echo 不大於 fi
4.3字串大小和檔案比較
字串比較 [root@eyu sbin]# cat len.sh #!/bin/bash if [ -n $1 ];then echo 長度大於零 else echo 空 fi if [ -z $1 ];then echo 空 else echo 長度大於零 fi [root@eyu sbin]# sh len.sh nihao 長度大於零 長度大於零 [root@eyu sbin]# sh len.sh 長度大於零 空 檔案比較 -d file 檢查檔案是否存在並且是目錄 -e file 檢查檔案是否存在 -f file 檢查問價是否存在並且是一個檔案 -r file 檢查檔案是否可讀 -s file 檢查檔案是否存在並且不為空 -w file 檢查檔案是否可寫 -x file 檢查檔案是否可執行 -O file 檢查檔案是否存在且被當前使用者擁有 -G file 檢查檔案是否存在且是當前使用者組 file1 -nt file2 檢查 檔案1是否比檔案2新 file1 -ot file2 檢查檔案1 是否比檔案2舊 *案例1 目錄物件檔案比較 [root@eyu sbin]# sh check.sh /etc/passwd 不是目錄 物件存在 是檔案 [root@yu sbin]# cat check.sh #!/bin/bash if [ -d $1 ];then echo 是目錄 else echo 不是目錄 fi if [ -e $1 ];then echo 物件存在 else echo 物件不存在 fi if [ -f $1 ];then echo 是檔案 else echo 不是檔案 fi *案例2 檔案屬組是否可讀比較 [root@eyu sbin]# sh check1.sh /etc/resolv.conf 檔案存在 檔案有可讀許可權 檔案是當前的使用者組 [root@eyu sbin]# cat check1.sh #!/bin/bash if [ -f $1 ];then echo 檔案存在 if [ -r $1 ];then echo 檔案有可讀許可權;else null;fi if [ -G $1 ];then echo 檔案是當前的使用者組;else null;fi else echo 檔案不存在 fi [root@eyu sbin]# ll -a /etc/resolv.conf -rw-r--r--. 1 root root 53 10月4 17:18 /etc/resolv.conf *案例3 檔案或資料夾是否有資料查詢 [root@eyu sbin]# sh null.sh 檔案或資料夾有資料 [root@eyu sbin]# sh null.sh kong.txt null [root@eyu sbin]# cat null.sh #!/bin/bash if [ -s $1 ];then echo 檔案或資料夾有資料 else echo null fi *案例4 檔案是否可寫可執行 [root@eyu sbin]# sh wr.sh /etc/passwd 可寫 null [root@eyu sbin]# chmod u+x wr.sh [root@eyu sbin]# ./wr.sh wr.sh 可寫 可執行 [root@eyu sbin]# ll -a wr.sh -rwxr--r--. 1 root root 118 10月5 00:17 wr.sh [root@eyu sbin]# cat wr.sh #!/bin/bash if [ -w $1 ];then echo 可寫 if [ -x $1 ];then echo 可執行;else echo null;fi else echo 不可寫 fi
5、複合條件檢查
在if-then中使用布林邏輯來合併檢查條件:
and *[ condition1 ]&& [ condition2 ] or *[ condition1 ]|| [ condition2 ] *案例 [root@eyu sbin]# ./wr.sh wr.sh 可寫可執行 [root@eyu sbin]# ./wr.sh /etc/passwd 可以或可執行或都沒有 [root@eyu sbin]# cat wr.sh if [ -w $1 ] && [ -x $1 ];then echo 可寫可執行 else echo 可以或可執行或都沒有 fi [root@eyu sbin]#
6、if-then的高階特徵
*雙圓括號表示數學表達數 *雙方括號表示高階字串處理函式
6.1雙圓括號命令符號 val++ 後自增、val--後自減、++val前自增、--val前自減、!邏輯否定、~取反、**取冪、<< 逐為左移、>> 逐位右移、&布林值與、|布林值或、&&邏輯與、||邏輯或 *案例 [root@eyu sbin]# sh towbrackets.sh 30 900 [root@eyu sbin]# sh towbrackets.sh 1 小於 [root@eyu sbin]# cat towbrackets.sh #!/bin/bash if (( $1 ** 2 > 90));then (( a = $1 ** 2 )) echo $a else echo 小於 fi 6.2使用雙方括號 格式 [[ expression ]] 雙括號裡用的expression使用在test命令中,給test命令帶來了一個功能叫: 模式匹配 在模式匹配中可以定義字串匹配的正則表示式 *案例 [root@hzy sbin]# sh user.sh 是 [root@hzy sbin]# cat user.sh #!/bin/bash if [[ $USER == ro* ]];then echo 是 else echo 不是 fi
7、case命令
語法:
case variable in pattern 1 | pattern2) commands;; pattern 3) commands;; *) commands;; esac
在一組資料中找固定的值,這種情況就需要多次呼叫if-then-else語句,如下所示:
[root@hzy sbin]# sh userif.sh 當前使用者是root [root@hzy sbin]# cat userif.sh #!/bin/bash if [ $USER == root ];then echo 當前使用者是$USER elif [ $USER == bob ];then echo 當前使用者是$USER elif [ $USER == boc ];then echo 當前使用者是$USER else echo 沒有這個使用者 fi
像這種多次呼叫elif的語句可以用case命令簡寫:
[root@hzy sbin]# sh userif.sh root, bob, boc 是列表中的root [root@hzy sbin]# cat userif.sh #!/bin/bash list="root, bob, boc" echo $list case $USER in root | bob | boc) echo 是列表中的$USER;; *) echo 沒有列表中的使用者 esac [root@hzy sbin]#
8、for命令
表示式格式是:
for var in list do commands done
這個命令是一種常見的程式設計命令。通常用來重複一系列命令,直到滿足一個特定的值或條件迭代結束。
8.1 讀取列表中的值
for命令的最基本的使用方法是通過for命令中定義的一列值來迭代
[root@hzy sbin]# sh list.sh next start nihao next start wo next start shi next start shei [root@hzy sbin]# cat list.sh #!/bin/bash for i in nihao wo shi shei do echo next start $i done [root@hzy sbin]#
8.2 讀取列表中的複雜值
I don't know if this'll work
[root@hzy sbin]# sh list.sh next start:I next start:dont know if thisll next start:work [root@hzy sbin]# cat list.sh #!/bin/bash for i in I don't know if this'll work do echo next start:$i done 忽然發現在列表中出現了'號,然後出來的值順序發生了變化。 像這種情況有倆種解決辦法: *使用轉義字元(反斜槓)來轉義單引號; *使用雙引號來定義使用單引號的值。 案例 [root@hzy sbin]# sh list.sh next start:I next start:dont know if thisll next start:work -------------------------------------------------------------------- next start:I next start:don't next start:know next start:if next start:this'll next start:work ------------------------------------------------------------------- next start:I don't know if this'll work ------------------------------------------------------------------- next start:I next start: don't next start:know next start:if next start:this'll next start:work [root@hzy sbin]# cat list.sh #!/bin/bash for i in I don't know if this'll work do echo next start:$i done echo -------------------------------------------------------------------- for i in I don\'t know if this\'ll work ##1 do echo next start:$i done echo ------------------------------------------------------------------- for i in "I don't know if this'll work"##2 do echo next start:$i done echo ------------------------------------------------------------------- for i in "I" " don't" "know" "if" "this'll" "work"##2 do echo next start:$i done
8.3 從變數讀取列表
[root@hzy sbin]# sh list1.sh Content viewed root; Content viewed bob; Content viewed gc; Content viewed goc; Content viewed admin; Content viewed tccapache; [root@hzy sbin]# cat list1.sh #!/bin/bash list="root bob gc goc admin tcc" list=$list"apache" for i in $list do echo "Content viewed $i;" done
8.4 讀取命令中的值
[root@hzy sbin]# sh list2.sh Content viewed on user roo; Content viewed on user apache; Content viewed on user pas; Content viewed on user bob; Content viewed on user hz; Content viewed on user gouzhi; Content viewed on user wanghao; [root@hzy sbin]# cat list2.sh #!/bin/bash for i in `cat user.txt` do echo "Content viewed on user $i;" done [root@hzy sbin]# cat user.txt roo apache pas bob hz gouzhi wanghao
8.5 改變shell的欄位分割符
在預設情況下,bash shell 的預設分割符是:
*空格; *製表符; *換行符。
修改預設環境變數IFS的值,限制bash shell 看作是欄位分割字元的字元。
案例1 [root@hzy sbin]# sh list3.sh list this is user roo list this is user apache list this is user pas list this is user bob list this is user hz list this is user gouzhi list this is user wanghao list this is user roo apache pas bob hz gouzhi wanghao list this is user roo apache pas bob hz gouzhi wanghao [root@hzy sbin]# cat user.txt roo apache pas bob hz gouzhi wanghao 由於user.txt檔案的格式使用的是換行符,所以只有限定IFS為換行符時執行了遍歷。 案例2 [root@hzy sbin]# sh test.sh root x 0 0 root /root /bin/bash bin x 1 1 bin /bin /sbin/nologin [root@hzy sbin]# cat test.sh #!/bin/bash IFS=$'\n':#限定多個分割符 for i in `cat /etc/passwd |head -n 2` do echo $i done
8.6 使用萬用字元讀取目錄
檔案通配是生成與指定萬用字元匹配的檔案或路徑名的過程
[root@hzy sbin]# cat wildcard.sh #!/bin/bash for i in /var/log/* do if [ -d $i ];then echo 輸出目錄$i elif [ -f $i ];then echo 輸出檔案$i fi done [root@hzy sbin]# sh wildcard.sh 輸出目錄/var/log/anaconda 輸出目錄/var/log/audit 輸出檔案/var/log/boot.log 輸出檔案/var/log/boot.log-20180626 輸出檔案/var/log/boot.log-20180627 輸出檔案/var/log/boot.log-20181004 輸出檔案/var/log/boot.log-20181006 輸出檔案/var/log/btmp 輸出檔案/var/log/btmp-20181003 輸出目錄/var/log/chrony ...
9.C式的for命令
9.1 C語言中的for命令
for (i = 0 ; i < 10 ; i ++) { printf ("The next number is %d\n" , i); } 一個簡單的自增迭代式 [root@hzy sbin]# sh for.sh The next number is 0 The next number is 1 The next number is 2 The next number is 3 The next number is 4 The next number is 5 The next number is 6 The next number is 7 The next number is 8 The next number is 9 The next number is 10 The next number is 11 The next number is 12 The next number is 13 The next number is 14 The next number is 15 The next number is 16 The next number is 17 The next number is 18 The next number is 19 The next number is 20 [root@hzy sbin]# cat for.sh #!/bin/bash for (( i=0; i <=20; i++ )) do echo "The next number is $i" done
9.2 使用多個變數
c式的for命令同樣可以使用多個變數迭代:
[root@hzy sbin]# sh for.sh 1 - 10 2 - 9 3 - 8 4 - 7 5 - 6 6 - 5 7 - 4 8 - 3 9 - 2 10 - 1 [root@hzy sbin]# cat for.sh #!/bin/bash for (( i=1, b=10; i <= 10; i++, b-- )) do echo "$i - $b" done
10、while 命令
while命令的格式:
while test command do other command done 案例 [root@hzy sbin]# sh while.sh 10 9 8 7 6 5 4 3 2 1 [root@hzy sbin]# cat while.sh #!/bin/bash number=10 while [ $number -gt 0 ] do echo $number number=$[ $number - 1 ] done [root@hzy sbin]#
10.1 使用多個條測試命令
[root@hzy sbin]# sh while.sh 10 9 8 7 6 5 [root@hzy sbin]# cat while.sh #!/bin/bash number=10 while [ $number -gt 0 ] ##設定大於0 [ $number -ge 5 ] ##設定大於等於5 do echo $number number=$[ $number - 1 ] done *while命令允許在while語句行定義多條test命令。只有最後一條測試命令的退出狀態是用來決定迴圈是如何停止的。
11、until命令
這個命令測試的結果和while相反,只測試退出狀態為非0的情況,退出狀態為非0,迴圈停止。
until的命令格式:
until test commands do other commands done 案例 [root@hzy sbin]# sh -x until.sh + a=100 + '[' 100 -eq 0 ']' + echo 100 100 + a=75 + '[' 75 -eq 0 ']' + echo 75 75 + a=50 + '[' 50 -eq 0 ']' + echo 50 50 + a=25 + '[' 25 -eq 0 ']' + echo 25 25 + a=0 + '[' 0 -eq 0 ']' [root@hzy sbin]# cat until.sh #!/bin/bash a=100 until [ $a -eq 0 ] do echo $a a=$[ $a - 25 ] done 依次判斷直到a=0時退出迴圈
12、巢狀迴圈
while和for的巢狀 [root@hzy sbin]# sh while-for.sh Input 10 input sum的值10 input sum的值11 Input 9 input sum的值9 input sum的值10 Input 8 input sum的值8 input sum的值9 Input 7 input sum的值7 input sum的值8 Input 6 input sum的值6 ... [root@hzy sbin]# cat while-for.sh #!/bin/bash a=10 while [ $a -ge 0 ] do echo "Input $a" for (( i = 0; $i < 2; i++ )) do sum=$[ $a + $i ] echo "input sum的值$sum" done a=$[ $a - 1] done
13、檔案資料的迴圈
這裡需要結合
*使用巢狀迴圈 *更改環境變數IFS
... adm:x:3:4:adm:/var/adm:/sbi - value-key: adm value-key: x value-key: 3 value-key: 4 value-key: adm value-key: /var/adm value-key: /sbi Values in / - value-key: / Values in ologi - value-key: ologi [root@hzy sbin]# cat file.sh #!/bin/bash #IFS.OLD=$IFS IFS='\n' for i in `cat /etc/passwd |head -n 4` do echo "Values in $i -" IFS=: for z in $i do echo "value-key: $z" done #IFS=$IFS.OLD done
14、迴圈的控制
迴圈不一定執行完,對於迴圈的控制需要用到倆個命令:
break命令: continue命令。
14.1 break命令
這個命令是跳出迴圈
[root@hzy sbin]# sh break.sh ---------------5------------ [root@hzy sbin]# cat break.sh #!/bin/bash for i in `seq 1 10` do if [ $i -eq 5 ];then break fi done echo ---------------$i------------ ##不加break,正常情況這個$i會輸出1-10 這個命令同樣適用於while和until迴圈
14.2 continue命令
跳出迴圈後繼續執行
[root@hzy sbin]# sh continue.sh ----------------------1------------------- ----------------------2------------------- ----------------------3------------------- ----------------------4------------------- ----------------------6------------------- ----------------------7------------------- ----------------------8------------------- ----------------------9------------------- ----------------------11------------------- ----------------------12------------------- ----------------------13------------------- ----------------------14------------------- ----------------------15------------------- ----------------------16------------------- ----------------------17------------------- ----------------------18------------------- ----------------------19------------------- ----------------------20------------------- [root@hzy sbin]# cat continue.sh #!/bin/bash for i in `seq 1 20` do case $i in 5 ) continue ;; 10) continue ;; esac echo ----------------------$i------------------- ##這裡只是跳過了5和10 done
15、處理迴圈的輸出
最後,可以在shell指令碼中使用管道或重定向的方式輸出結果。通過在done命令的末尾新增處理命令實現
*重定向 [root@hzy sbin]# cat output.txt 輸出檔案--/home/all-in-one 輸出目錄--/home/hzy 輸出目錄--/home/kolla-ansible 輸出檔案--/home/multinode [root@hzy sbin]# cat yy.sh #!/bin/bash for i in /home/* do if [ -d $i ];then echo "輸出目錄--$i" elif [ -f $i ];then echo "輸出檔案--$i" fi done > output.txt *管道符號 [root@hzy sbin]# sh sort.sh 123----------------- aFASDF----------------- aff----------------- asA----------------- fsdf222----------------- s2234----------------- [root@hzy sbin]# cat sort.sh #!/bin/bash for i in 123 aff s2234 asA aFASDF fsdf222 do echo $i----------------- done | sort
END