1. 程式人生 > >02 . Shell變數和邏輯判斷及迴圈使用

02 . Shell變數和邏輯判斷及迴圈使用

#### Shell變數 ##### 系統變數 > 在命令列提示符直接執行 env、set 檢視系統或環境變數。env 顯示使用者環境變數,set 顯示 Shell預先定義好的變數以及使用者變數。可以通過 export 匯出成使用者變數。 `一些寫Shell指令碼時常用的系統變數` ```python $SHELL 預設 Shell $HOME 當前使用者家目錄 $IFS 內部欄位分隔符 $LANG 預設語言 $PATH 預設可執行程式路徑 $PWD 當前目錄 $UID 當前使用者 ID $USER 當前使用者 $HISTSIZE 歷史命令大小,可通過 HISTTIMEFORMAT 變數設定命令執行時間 $RANDOM 隨機生成一個 0 至 32767 的整數 $HOSTNAME 主機名 ``` ##### 普通變數與臨時環境變數 > 普通變數定義:VAR=value > > 臨時環境變數定義:export VAR=value > > 變數引用:$VAR > > 下面看下他們之間區別: > > Shell 程序的環境變數作用域是 Shell 程序,當 export 匯入到系統變數時,則作用域是 Shell 程序及其 Shell 子程序。 > > Shell 程序的環境變數作用域是 Shell 程序,當 export 匯入到系統變數時,則作用域是 Shell 程序及其 Shell 子程序。 > > ps axjf 輸出的第一列是 PPID(父程序 ID),第二列是 PID(子程序 ID)當SSH 連線 Shell 時,當前終端 PPID(-bash)是 sshd 守護程式的 PID(root@pts/0),因此在當前終端下的所有程序的 PPID 都是-bash 的 PID,比如執行命令、執行指令碼。 > > 所以當在-bash 下設定的變數,只在-bash 程序下有效,而-bash 下的子程序 bash 是無效的,當export 後才有效。 > > 進一步說明:再重新連線 SSH,去除上面定義的變數測試下所以在當前 shell 定義的變數一定要 export,否則在寫指令碼時,會引用不到。 > > 還需要注意的是退出終端後,所有使用者定義的變數都會清除。 > > 在/etc/profile 下定義的變數就是這個原理. ##### 位置變數 > 位置變數指的是函式或指令碼後跟的第 n 個引數。 > > 1−1−n,需要注意的是從第 10 個開始要用花括號呼叫,例如${10} > > shift 可對位置變數控制,例如: ```python #!/bin/bash echo "1: $1" shift echo "2: $2" shift echo "3: $3" sh test.sh 1 2 3 1: 1 2: 3 3: # 每執行一次 shift 命令,位置變數個數就會減一,而變數值則提前一位。shift n,可設定向前移動n位。 ``` ##### 特殊變數 ```python $0 # 指令碼自身名字 $? # 返回上一條命令是否執行成功,0 為執行成功,非 0 則為執行失敗 $# # 位置引數總數 $* # 所有的位置引數被看做一個字串 $@ # 每個位置引數被看做獨立的字串 $$ # 當前程序 PID $! # 上一條執行後臺程序的 PID ``` ##### 變數引用 | 賦值運算子 | 示例 | | ---------- | ------------ | | = | 變數賦值 | | += | 兩個變數相加 | ##### 自定義變數與引用 ```python a=123 echo $a 123 a+=456 echo $a 123456 # Shell 中所有變數引用使用$符,後跟變數名 # 有時個別特殊字元會影響正常使用,就需要使用${a},例如 [root@redis ~]# b=123 [root@redis ~]# echo $b 123 [root@redis ~]# echo ${b} 123 # 有時個別特殊字元會影響正常引用,那麼需要使用${VAR} [root@redis ~]# echo $b123 [root@redis ~]# echo ${b}123 123123 # 將命令結果作為變數值 [root@redis ~]# c=`echo 123` [root@redis ~]# echo $c 123 [root@redis ~]# c=$(echo 123) [root@redis ~]# echo $c 123 # 這裡的反撇號等效於$(),都是用於執行 Shell 命令。 # 單引號和雙引號 [root@redis ~]# d=1 [root@redis ~]# d="1 2 $d" [root@redis ~]# echo $d 1 2 1 [root@redis ~]# c=1 [root@redis ~]# c='1 2 $c' [root@redis ~]# echo $c 1 2 $c # 單引號是告訴 Shell 忽略特殊字元,而雙引號則解釋特殊符號原有的意義,比如$ 、 !。 ``` ##### Shell變數的輸入 > Shell變數除了可以直接賦值或指令碼傳參外,還可以使用read命令從標準輸入獲得,read為bash內建命令,可以通過help read檢視幫助 `語法格式` ```python # read [引數] [變數名] ``` `常用引數` ```python # -p prompt: 設定提示資訊 # -t timeout: 設定輸入等待的事件,單位預設為秒 ``` `read的基本讀入` `如果不加-t read就會一直等待` ```python # read後面的引數是一個變數 [root@youmen ~]# read -p 'please input you num:' num please input you num:234 [root@youmen ~]# echo $num 234 # 設定超時事件為3秒 read -t 3 -p "please input you num:" num please input you num: # 過3秒鐘會指令碼會自己執行結束 ``` `read在指令碼中常用例子` ```python [root@youmen ~]# sh test.sh please input you num: 1 2 1-2 =-1 1+2 =3 1*2 =2 1/2 =0 1**2 =1 1%2 =1 [root@youmen ~]# cat abc.sh #!/bin/bash read -t 18 -p "please input you num:" a b echo "$a-$b =$(( $a - $b ))" echo "$a+$b =$(( $a + $b ))" echo "$a*$b =$(( $a * $b ))" echo "$a/$b =$(( $a / $b ))" echo "$a**$b =$(( $a ** $b ))" echo "$a%$b =$(( $a % $b ))" # 利用echo 命令替代和read -p的功能 [root@youmen ~]# cat test.sh #!/bin/bash echo -n "請輸入兩個數字:" read a b echo "$a+$b =$(( $a + $b ))" echo "$a*$b =$(( $a * $b ))" echo "$a/$b =$(( $a / $b ))" echo "$a**$b =$(( $a ** $b ))" echo "$a%$b =$(( $a % $b ))" [root@youmen ~]# bash test.sh 請輸入兩個數字:2 3 2+3 =5 2*3 =6 2/3 =0 2**3 =8 2%3 =2 ``` #### 條件測試與比較 ##### 介紹 > 在bash的各種流程控制結構中通常要進行各種測試,然後根據測試結果執行不同的操作,有時也會通過與if等條件語句相結合,更方便的完成判斷 `條件測試通常由如下3種語法形式` ```python # 語法1:test<測試表達式> # 語法2:[<測試表達式>] # 語法3:[[<測試表達式>]] # 說明 # 1.上述語法格式1和語法格式2的寫法是相等的。語法格式3為擴充套件的test命令。推薦使用語法格式2. # 2.在[[]]中可以使用萬用字元進行模式匹配。&&、||、>、<等操作可以應用於[[]]中,但不能應用於[]中. # 3.對於整數的關係運算,也可以使用Shell的算術運算子(()) ``` ##### test測試表達式 ```python # 判斷是不是檔案 [root@youmen ~]# test -f /etc/hosts [root@youmen ~]# echo $? 0 [root@youmen ~]# test -f /etc/hostss [root@youmen ~]# echo $? 1 # 判斷檔案是否可以執行 [root@youmen ~]# test -x /usr/bin/ssh [root@youmen ~]# echo $? 0 [root@youmen ~]# test -x /etc/hosts [root@youmen ~]# echo $? 1 # 判斷是不是目錄 [root@youmen ~]# test -d /etc/ [root@youmen ~]# echo $? 0 [root@youmen ~]# test -d /etc/hosts [root@youmen ~]# echo $? 1 ``` ##### []中括號表示式 ```python # 判斷是不是普通檔案 [root@youmen ~]# [ -f /etc/hosts ] [root@youmen ~]# echo $? 0 [root@youmen ~]# [ -f /etc/hostss ] [root@youmen ~]# echo $? 1 # 判斷是否是目錄 [root@youmen ~]# [ -d /etc/hosts ] [root@youmen ~]# echo $? 1 [root@youmen ~]# [ -d /etc/ ] [root@youmen ~]# echo $? 0 # 判斷是否可被執行 [root@youmen ~]# [ -x /etc/hosts ] [root@youmen ~]# echo $? 1 [root@youmen ~]# [ -x /usr/bin/ssh ] [root@youmen ~]# echo $? 0 ``` ##### [[雙括號表示式]] ```python [root@youmen ~]# [[ -x /etc/hosts ]] [root@youmen ~]# echo $? 1 [root@youmen ~]# [[ -x /usr/bin/ssh ]] [root@youmen ~]# echo $? 0 # [[]] 和[]一樣 # 區別是可以在多括號裡面新增多個判斷 # 例如判斷是不是目錄,並判斷下一個檔案是不是可執行 [root@youmen ~]# [[ -d /etc/ && -x /usr/bin/ssh ]] [root@youmen ~]# echo $? 0 [root@youmen ~]# [[ -d /etc/ && -x /usr/bin/sshdd ]] [root@youmen ~]# echo $? 1 # &&只在雙括號裡面有效,如果單括號裡面需要使用-a,-o ``` ##### 檔案測試表達式 ```python 操作符 說明 舉例 # -b file 檢測檔案是否是塊裝置檔案,如果是,則返回 true。 [ -b $file ] 返回 false。 # -c file 檢測檔案是否是字元裝置檔案,如果是,則返回 true。 [ -c $file ] 返回 false。 # -d file 檢測檔案是否是目錄,如果是,則返回 true。 [ -d $file ] 返回 false。 # -f file 檢測檔案是否是普通檔案(既不是目錄,也不是裝置檔案),如果是,則返回 true。 [ -f $file ] 返回 true。 # -g file 檢測檔案是否設定了 SGID 位,如果是,則返回 true。 [ -g $file ] 返回 false。 # -k file 檢測檔案是否設定了粘著位(Sticky Bit),如果是,則返回 true。 [ -k $file ] 返回 false。 # -p file 檢測檔案是否是具名管道,如果是,則返回 true。 [ -p $file ] 返回 false。 # -u file 檢測檔案是否設定了 SUID 位,如果是,則返回 true。 [ -u $file ] 返回 false。 # -r file 檢測檔案是否可讀,如果是,則返回 true。 [ -r $file ] 返回 true。 # -w file 檢測檔案是否可寫,如果是,則返回 true。 [ -w $file ] 返回 true。 # -x file 檢測檔案是否可執行,如果是,則返回 true。 [ -x $file ] 返回 true。 # -s file 檢測檔案是否為空(檔案大小是否大於0),不為空返回 true。 [ -s $file ] 返回 true。 # -e file 檢測檔案(包括目錄)是否存在,如果是,則返回 true。 [ -e $file ] 返回 true。 # 特別說明:這些操作符號對於[[]]、[]、test幾乎都是通用的, ``` #### 字串表示式 >
字串測試操作符的作用有:比較兩個字串是否相同、字串的長度是否為零,字串是否為NULL(注:bash區分零長度字串和空字串)等 > > **常用字串測試操作符** **說明** -z “字串” 若串長度為0則真,-z可以理解為zero -n ”字串“ 若昂度不為0則真,-n 可以理解為no zero ”串1“ = ”串2“ > > 若串1等於串2則真,可以使用”==“代替”=“ > > “串2” != “串2” > > 若串1不等於串2則真,不能用“!==“ 代替”!=“ 特別注意: ```python # 1. 以上表格中的字串測試操作符號務必要用”“引起來。 # 2.比較符號兩端有空格 ``` `字串測試操作符提示` ```python # 1)-n 比較字串長度是否不為零,如果不為零則為真,如:[ -n “$myvar” ] # 2)-z 比較字串長度是否等於零,如果等於零則為真,如:[ -z “$myvar” ] # 特別注意 # 對於以上表格中的字串測試操作符號,如[ -n “$myvar” ],要把字串用“”引起來。 # 1、字串或字串變數比較都要加雙引號之後再比較。 # 2、字串或字串變數比較,比較符號兩端最好都有空格,可以參考系統指令碼 # “=”比較兩個字串是否相同,與“==”等價,如[ “$a” = “$b” ]其中$a這樣的變數最好用“”括起來,因為如果中間由空格,*等符號就可能出錯,更好的辦法就是[ “${a}” = “${b}” ] # “!=” 比較兩個字串是否相同,不同則為“是” ``` #### 邏輯操作符 >
在[]和test中使用 在[[]]中使用 說明 -a && and與,兩端都為真,則真 -o || or或,兩端有一個為真則真 ! ! not非,相反則為真 ```python # !中文意思是反:與一個邏輯值相關的邏輯值 # -a 中文意思是(and|&&):兩個邏輯值都為“真”,返回值才為“真”,反之為“假” # -o 中文意思是或(or| ||):兩個邏輯值只要有一個為“真”,返回值就為“真” # 邏輯操作運算規則 # -a和&& 的運算規則:只有兩端都是1才為真 # 要想使用&&注意雙括號 ``` #### Shell流程控制 ##### If `if 語句語法格式` ```python if condition then command1 command2 ... commandN fi # 寫成一行 if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi ``` ##### If else `if else語法格式` ```python if condition then command1 command2 ... commandN else command fi ``` ##### if else-if else `if else-if else語法格式` ```` if condition1 then command1 elif condition2 then command2 else commandN fi ```` `例項` ```python a=10 b=20 if [ $a == $b ] then echo "a 等於 b" elif [ $a -gt $b ] then echo "a 大於 b" elif [ $a -lt $b ] then echo "a 小於 b" else echo "沒有符合的條件" fi # a 小於 b ``` `if else語句經常與test命令結合使用,如下所示` ```python num1=$[2*3] num2=$[1+5] if test $[num1] -eq $[num2] then echo '兩個數字相等!' else echo '兩個數字不相等!' fi # 輸出結果 # 兩個數字相等! ``` #### 迴圈 ##### for `語法格式` ```python for var in item1 item2 ... itemN do command1 command2 ... commandN done # 寫成一行 for var in item1 item2 ... itemN; do command1; command2… done; # 當變數值在列表裡,for迴圈即執行一次所有命令,使用變數名獲取列表中的當前取值。 # 命令可為任何有效的shell命令和語句。in列表可以包含替換、字串和檔名。 # in列表是可選的,如果不用它,for迴圈使用命令列的位置引數。 # 順序輸出當前列表中的數字 for loop in 1 2 3 4 5 do echo "The value is: $loop" done # 輸出 The value is: 1 The value is: 2 The value is: 3 The value is: 4 The value is: 5 # 順序輸出字串中的字元 for str in 'This is a string' do echo $str done # 輸出結果 This is a string ``` ##### While `while迴圈用於不斷執行一系列命令,也用於從輸入檔案中讀取資料;命令通常為測試條件。其格式為:` ```python while condition do command done ``` `一下是一個基本的while迴圈,測試條件是,如果int小於等於5,那麼條件返回真。int從0開始,每次迴圈處理時,int加1。執行上述指令碼,返回數字1到5,然後終止。` ```python #!/bin/bash int=1 while(( $int<=5 )) do echo $int let "int++" done # 輸出 1 2 3 4 5 # 以上例項使用了 Bash let 命令,它用於執行一個或多個表示式,變數計算中不需要加上 $ 來表示變數 # while迴圈可用於讀取鍵盤資訊。下面的例子中,輸入資訊被設定為變數FILM,按結束迴圈 echo '按下 退出' echo -n '輸入你最喜歡的網站名: ' while read FILM do echo "是的!$FILM 是一個好網站" done # 執行指令碼,輸出類似下面 按下 退出 輸入你最喜歡的網站名: youmeblog 是的!youmenblog 是一個好部落格 ``` ##### 無限迴圈 `無限迴圈語法格式` ```python while : do command done # or while true do command done # or for (( ; ;)) ``` ##### until迴圈 > until 迴圈執行一系列命令直至條件為 true 時停止。 > > until 迴圈與 while 迴圈在處理方式上剛好相反。 > > 一般 while 迴圈優於 until 迴圈,但在某些時候—也只是極少數情況下,until 迴圈更加有用。 `until 語法格式` ```python until condition do command done ``` > condition 一般為條件表示式,如果返回值為 false,則繼續執行迴圈體內的語句,否則跳出迴圈。 > > 以下例項我們使用 until 命令來輸出 0 ~ 9 的數字: ```python #!/bin/bash a=0 until [ ! $a -lt 10 ] do echo $a a=`expr $a + 1` done # 執行結果 0 1 2 3 4 5 6 7 8 9 ``` ##### case `Shell case語句為多選擇語句。可以用case語句匹配一個值與一個模式,如果匹配成功,執行相匹配的命令。case語句格式如下:` ```python case 值 in 模式1) command1 command2 ... commandN ;; 模式2) command1 command2 ... commandN ;; esac ``` > case工作方式如上所示。取值後面必須為單詞in,每一模式必須以右括號結束。取值可以為變數或常數。匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;。 > > 取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令後不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行後面的命令。 > > 下面的指令碼提示輸入1到4,與每一種模式進行匹配: ```python echo '輸入 1 到 4 之間的數字:' echo '你輸入的數字為:' read aNum case $aNum in 1) echo '你選擇了 1' ;; 2) echo '你選擇了 2' ;; 3) echo '你選擇了 3' ;; 4) echo '你選擇了 4' ;; *) echo '你沒有輸入 1 到 4 之間的數字' ;; esac # 輸入不同的內容,會有不同的結果,例如: 輸入 1 到 4 之間的數字: 你輸入的數字為: 3 你選擇了 3 ``` ##### break `break命令允許跳出所有迴圈(終止執行後面的所有迴圈)` `下面的例子中,指令碼進入死迴圈直至使用者輸入數字大於5。要跳出這個迴圈,返回到shell提示符下,需要使用break命令` ```python #!/bin/bash while : do echo -n "輸入 1 到 5 之間的數字:" read aNum case $aNum in 1|2|3|4|5) echo "你輸入的數字為 $aNum!" ;; *) echo "你輸入的數字不是 1 到 5 之間的! 遊戲結束" break ;; esac done # 執行以上程式碼,輸出結果為 輸入 1 到 5 之間的數字:3 你輸入的數字為 3! 輸入 1 到 5 之間的數字:7 你輸入的數字不是 1 到 5 之間的! 遊戲結束 ``` ##### continue `continue命令與break命令類似,只有一點差別,它不會跳出所有迴圈,僅僅跳出當前迴圈。對上面的例子進行修改:` ```python #!/bin/bash while : do echo -n "輸入 1 到 5 之間的數字: " read aNum case $aNum in 1|2|3|4|5) echo "你輸入的數字為 $aNum!" ;; *) echo "你輸入的數字不是 1 到 5 之間的!" continue echo "遊戲結束" ;; esac done ``` ##### Case..esac > **case ... esac** 與其他語言中的 switch ... case 語句類似,是一種多分枝選擇結構,每個 case 分支用右圓括號開始,用兩個分號 **;;** 表示 break,即執行結束,跳出整個 case ... esac 語句,esac(就是 case 反過來)作為結束標記。 > > case ... esac 語法格式如下 ```python case 值 in 模式1) command1 command2 command3 ;; 模式2) command1 command2 command3 ;; *) command1 command2 command3 ;; esac # case後為取值,值可以為變數或常數 # 值後為關鍵字 in,接下來是匹配的各種模式,每一模式最後必須以右括號結束,模式支援正則表示式。 #!/bin/sh site="runoob" case "$site" in "runoob") echo "youmen部落格" ;; "google") echo "Google 搜尋" ;; "taobao") echo "淘寶網" ;; e