1. 程式人生 > >Shell程式設計(二)

Shell程式設計(二)

Bash break break是退出迴圈的一個簡單方法, 用break命令來退出任意型別的迴圈,包括while和until迴圈 退出單個迴圈: for的break [[email protected] ~]# more s1.sh #!/bin/bash for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ var1eq5]thenbreakfiecho"Iterationnumber:var1 -eq 5 ] then break fi echo "Iteration number:

breakfiecho"Iterationnumber:var1" done echo “The for loop is completed” [[email protected] ~]# sh s1.sh Iteration number:1 Iteration number:2 Iteration number:3 Iteration number:4 The for loop is completed

while的break [[email protected] ~]# more s2.sh #!/bin/bash var1=1 while [ $var1 -lt 10 ] do if [ v

ar1eq5]thenbreakfiecho"Iteration:var1 -eq 5 ] then break fi echo "Iteration:var1" var1=[[var1+1] done echo “The while loop is completed” [[email protected] ~]# sh s2.sh Iteration:1 Iteration:2 Iteration:3 Iteration:4 The while loop is completed

跳出外部迴圈 break -n;n指定了要跳出的迴圈層級,預設為1,表明跳出的是當前的迴圈,n為2,break就會停止下一級 [[email protected] ~]# more s3.sh #!/bin/bash for((a=1;a<4;a++)) do echo “Outer loop:$a” for((b=1;b<100;b++)) do if [ bgt4]thenbreak2fiecho&quot;Innerloop:b -gt 4 ] then break 2 fi echo &quot;Inner loop:b" done done [[email protected] ~]# sh s3.sh Outer loop:1 Inner loop:1 Inner loop:2 Inner loop:3 Inner loop:4

Bash case case variable in pattern1 | pattern2) commands1;; pattern3 ) commands2;; ) default commands;; esac pattern1是正則表示式,可以用下面字元: ? [abc] [a-n] |

[[email protected] ~]# more s1.sh #!/bin/bash if [ $USER = “rich” ] then echo “Welcome $USER” echo “Please enjoy your visit” elif [ $USER = “barbara” ] then echo “Welcome $USER” echo “Please enjoy your visit” elif [ $USER = “testing” ] then echo “Special testing account” elif [ $USER = “jessica” ] then echo “Do not forget to logout when you’re done” else echo “Sorry,you are not allowed here” fi [[email protected] ~]# sh s1.sh Sorry,you are not allowed here elif語句繼續if-then檢查,為比較變數尋找特定的值。 有了case命令,就不需要在寫所有elif語句來不停檢查同一個變數的值了

[[email protected] ~]# more s1.sh #!/bin/bash case $USER in rich | barbara ) echo “Welcome $USER” echo “Please enjoy your visit”;; testing) echo “Special testing account”;; jessica) echo “Do not forget to logout when you’re done”;; *) echo “Sorry,you are not allowed here”;; esac

[[email protected] ~]# sh s1.sh Sorry,you are not allowed here

Bash測試引數 使用引數前一定要檢查其中是否存在資料 [[email protected] ~]# more s7.sh #!/bin/bash if [ -n “$1” ] -n檢測$1是否有資料 then echo “hello $1,glad to meet you” else echo “Sorry,you did not identify yourself” fi [[email protected] ~]# sh s7.sh Sorry,you did not identify yourself [[email protected] ~]# sh s7.sh tom hello tom,glad to meet you

Bash使用者輸入 命令列引數 ./s1.sh 10 20 向s1指令碼傳遞兩個引數10和20 指令碼會通過特殊的變數來處理引數 讀取引數 shell會將一些位置引數的 特殊變數輸入到命令列中的所有引數 位置引數的標準表示,$0是程式嗎,$1是第一個引數,以此類推,直到$9

單個命令引數 [[email protected] ~]# more s1.sh #!/bin/bash factoria1=1 for((number=1; number<=1;number++))dofactoria1=1 ;number++)) do factoria1=[ $factoria1 * $number ] done echo “The factorial of $1 is $factoria1” [[email protected] ~]# sh s1.sh 5 The factorial of 5 is 120

多個命令引數 如果需要輸入更多的命令列引數,則每個引數必須用空格分開 [[email protected] ~]# more s2.sh #!/bin/bash total=$[$1*$2] echo “The first parameter is $1” echo “The first parameter is $2” echo “The first parameter is $total” [[email protected] ~]# sh s2.sh 2 10 The first parameter is 2 The first parameter is 10 The first parameter is 20 shell會將每個引數分配給對應的變數

文字字元 [[email protected] ~]# more s3.sh #!/bin/bash echo hello $1,glad to meet you [[email protected] ~]# sh s3.sh hello ,glad to meet you [[email protected] ~]# sh s3.sh tim hello tim,glad to meet you [[email protected] ~]# sh s3.sh 'Tim jack hello Tim jack,glad to meet you 有空格的字元必須要使用引號

(以前版本)如果指令碼引數超過9個,仍然可以處理,需要修改變數名。在第9個變數後,在變數前加KaTeX parse error: Expected 'EOF', got '#' at position 24: …[email protected] ~]#̲ more s4.sh #!/…[10{10}*{11}] echo “The first parameter is ${10}” echo “The first parameter is ${11}” echo “The first parameter is $total” [[email protected] ~]# sh s4.sh 1 2 3 4 5 6 7 8 9 10 11 The first parameter is 10 The first parameter is 11 The first parameter is 110

讀取指令碼名,用$0引數獲取shell在命令列啟動的指令碼名 [[email protected] ~]# more s5.sh #!/bin/bash echo “The zero parameter is set to:$0” [[email protected] ~]# sh s5.sh The zero parameter is set to:s5.sh [[email protected] ~]# sh /root/s5.sh 顯示指令碼的完全路徑 The zero parameter is set to:/root/s5.sh

[[email protected] ~]# more s6.sh(basename,返回不包含路徑的指令碼) #!/bin/bash name=$(basename 0)echothescriptnameis:0) echo the script name is:name [[email protected] ~]# sh s6.sh the script name is:s6.sh [[email protected] ~]# sh /root/s6.sh the script name is:s6.sh

Bash 特殊引數變數 在bash shell中有些特殊變數 他們會記錄命令列引數 引數統計 $# [[email protected] ~]# more s8.sh #!/bin/bash echo “There were $# parameters supplied” [[email protected] ~]# sh s8.sh 1 There were 1 parameters supplied [[email protected] ~]# sh s8.sh 1 2 There were 2 parameters supplied [[email protected] ~]# sh s8.sh 1 2 3 4 There were 4 parameters supplied $#含有指令碼執行時攜帶的命令列引數的個數

[[email protected] ~]# more s9.sh #!/bin/bash if [$# -ne 2 ] then echo Usage: s9.sh a b else total=$[$1+$2] echo The total is KaTeX parse error: Expected 'EOF', got '#' at position 28: …[email protected] ~]#̲ sh s9.sh Usage…#變數來判斷命令列上有多少引數,然後在進行遍歷,你可以使用一組其他的特殊變數來解決這個問題 $* 變數會將所有引數當成單個引數 [email protected] 變數會單獨處理每個引數 [[email protected] ~]# more s10.sh #!/bin/bash echo echo “Using the $* method:$*” echo echo “Using the [email protected] method:[email protected]” [[email protected] ~]# sh s10.sh tom ssw alice

Using the $* method:tom ssw alice

Using the [email protected] method:tom ssw alice 從這個例子看無差別

[[email protected] ~]# more s11.sh #!/bin/bash count=1 for param in “[email protected]” do echo “[email protected] Parameter count=count=param” count=$[$count+1] done echo count=1 for param in “$*” do echo “$* Parameter $count=$param” count=$[$count+1] done

[[email protected] ~]# sh s11.sh tom ssw tim [email protected] Parameter 1=tom [email protected] Parameter 2=ssw [email protected] Parameter 3=tim

$* Parameter 1=tom ssw tim

Bash 使用者輸入 bash shell為此提供了read命令 read命令從標準輸入(鍵盤)或另一個檔案描述符中接受輸入。在收到輸入後,read命令會將資料放進一個變數 [[email protected] ~]# more s1.sh #!/bin/bash echo -n “Enter your name” -n不會在字串末尾換行 read name echo “Hello $name,welcome to my program” [[email protected] ~]# sh s1.sh Enter your name ssw Hello ssw,welcome to my program

[[email protected] ~]# more s2.sh #!/bin/bash read -p “please enter your age:” age -p命令列指定提示符 days=$[$age * 365 ] echo “That makes you over $days days old!” [[email protected] ~]# sh s2.sh please enter your age: 20 That makes you over 7300 days old!

[[email protected] ~]# more s3.sh #!/bin/bash read -p “Enter your name:” first last echo “Checking date for $last,$first…” [[email protected] ~]# sh s3.sh Enter your name:ssw cwf Checking date for cwf,ssw…

[[email protected] ~]# more s4.sh #!/bin/bash read -p “Enter your name:” echo echo “Hello $REPLY,welcome to my program” [[email protected] ~]# sh s4.sh Enter your name: ssw

Hello ssw,welcome to my program (read命令列中不指定變數,read命令會將它收到的任何資料都放進特殊環境變數REPLY中)

[[email protected] ~]# more s5.sh #!/bin/bash if read -t 5 -p “Please enter your name:” name (-t指定一個計時器 秒數) then echo “Hello,$name,welcome to my script” else echo echo “Sorry,too slow!” fi [[email protected] ~]# sh s5.sh Please enter your name: Sorry,too slow! [[email protected] ~]# sh s5.sh Please enter your name: ssw Hello,ssw,welcome to my script

[[email protected] ~]# more s6.sh #!/bin/bash read -n1 -p “Do you want to continue [Y/N]?” answer case $answer in (當輸入的字元達到預設的字元數時,就自動退出,將輸入的資料傳給變數) Y | y) echo echo “fine,continue on…”;; N | n) echo echo “ok goodbye” exit ;; esac [[email protected] ~]# sh s6.sh Do you want to continue [Y/N]?y fine,continue on… [[email protected] ~]#

要隱藏的資料型別,如輸入密碼 [[email protected] ~]# more s7.sh #!/bin/bash read -s -p “Enter your password:” pass -s隱藏 echo echo "Is your password really $pass? " [[email protected] ~]# sh s7.sh Enter your password: Is your password really 123456?

read讀取linux檔案中的檔案 [[email protected] ~]# more s8.sh #!/bin/bash count=1 cat /etc/passwd | while read line do echo “Line $count:$line” count=$[$count+1] done echo “Finished processing the file” while迴圈會持續通過read命令處理檔案中的行,直到read命令以非0退出狀態碼退出 基本的指令碼函式 函式是一個指令碼程式碼塊,你可以為其命名並在程式碼中任何位置重用。要在指令碼中使用該程式碼塊時,只要使用所起的函式名就行了(這個過程為呼叫函式) function name { name屬性定義了賦予函式的唯一名稱 commands commands是構成函式的一條或多條bash shell命令,按順序執行 }

[[email protected] ~]# more s1.sh #!/bin/bash function func1 { echo “This is an example of a function” } count=1 while [ countle5]dofunc1func1bashshellfunc1count=count -le 5 ] do func1 每次引用函式名func1時,bash shell會找到func1函式的定義並執行在那裡定義的命令 count=[$count+1] done echo “This is the end of the loop” func1 echo “Now this is the end of the script” [[email protected] ~]# sh s1.sh This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is the end of the loop This is an example of a function Now this is the end of the script

函式定義不一定非得是shell指令碼中首先要做的事,但一定要小心。如果在函式被定義前使用函式,你會收到一條錯誤資訊。 [[email protected] ~]# more s2.sh #!/bin/bash count=1 echo “This line comes before the function definition” function func1 { echo “This is an example of a function” } while [ countle5]dofunc1count=count -le 5 ] do func1 count=[$count+1] done echo “This is the end of the loop” func2 echo “Now this is the end of the script” function func2{ 由於func2函式還沒有定義,指令碼執行函式呼叫處時,產生一條錯誤訊息 echo “This is an example of a function” } [[email protected] ~]# sh s2.sh This line comes before the function definition This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is an example of a function This is the end of the loop s2.sh: line 13: func2: command not found Now this is the end of the script s2.sh: line 16: syntax error near unexpected token echo' s2.sh: line 16: echo “This is an example of a function”’

函式覆蓋 [[email protected] ~]# more s3.sh #!/bin/bash function func1 { echo “This is the first definition of the function name” } func1 func1函式最初的定義工作正常,但重新定義該函式後,後續的函式都會呼叫使用第二個定義 function func1 { echo “This is a repeat of the same function name” } func1 echo “This is the end of the script” [[email protected] ~]# sh s3.sh This is the first definition of the function name This is a repeat of the same function name This is the end of the script

返回值 函式的退出狀態碼 預設情況下,函式的退出狀態碼是函式中最後一條命令返回的退出狀態碼。在函式執行結束後,可以用標準變數KaTeX parse error: Expected 'EOF', got '#' at position 32: …[email protected] ~]#̲ more s4.sh #!/…?"

[[email protected] ~]# sh s4.sh testing the function: trying to display a non-existent file ls: cannot access file1: No such file or directory The exit status is:2 因為func1中命令沒有執行。 [[email protected] ~]# touch file1 [[email protected] ~]# sh s4.sh testing the function: trying to display a non-existent file -rw-r–r--. 1 root root 0 Nov 8 10:30 file1 The exit status is:0 函。數的退出狀態碼是2,這是因為函式中的最後一條命令沒有成功執行。但你無法知道函式中其他命令是否成功

[[email protected] ~]# more s5.sh #!/bin/bash func1(){ ls -l file echo “This was a test of a bad command” } echo “testing the function:” func1 echo “The exit status is:$?” [[email protected] ~]# sh s5.sh testing the function: ls: cannot access file: No such file or directory This was a test of a bad command The exit status is:0 由於函式最後一條語句echo執行成功,該函式的退出狀態碼就是0,儘管其中有一條命令沒有正常執行。使用函式的預設退出狀態是很危險的

return bash shell使用return命令來退出函式並返回特定的退出狀態碼;return命令允許指定一個整數值來定義函式的退出狀態碼,從而指定一種簡單的途徑來程式設計設定函式退出狀態碼 [[email protected] ~]# more s6.sh #!/bin/bash function db1 { read -p "Enter a value: " value echo “doubling the value” return $[$value2] } db1 echo “The new value is $?” [[email protected] ~]# sh s6.sh Enter a value: 2 doubling the value The new value is 4 db1函式會將$value變數中使用者輸入的值2,然後用return命令返回結果。指令碼用$?變數顯示了該值 但當用這種方法從函式中返回值時,要小心,下面兩條技巧避免問題: 1.函式一結束就取返回值 2.退出狀態碼必須是0-255 如果在用$?變數提取函式返回值之前執行了其他命令,函式的返回值就會丟失。記住,$?變數會返回執行的最後一條命令的退出狀態碼 返回值的取值範圍。由於退出狀態碼必須小於256,函式結果必須生成一個小於256的整數值。任何大於256的值都會產生一個錯誤值

使用函式輸出 和命令的輸出儲存到shell變數中一樣,也可以對函式的輸出採用同樣的處理辦法 [[email protected] ~]# more s7.sh #!/bin/bash function db1 { read -p “Enter a value:” value echo “$[$value*2 ]” } result=$(db1) 將db1函式的輸出賦給$result變數 echo “The new value is $result” [[email protected] ~]# sh s7.sh Enter a value: 3 The new value is 6

函式中使用變數 向函式傳遞引數 [[email protected] ~]# more s8.sh #!/bin/bash function addem { if [ $# -eq 0 ] || [ $# -gt 2 ] then echo -1 elif [ $# -eq 1 ] then echo $[$1+$1] else echo $[$1+KaTeX parse error: Expected 'EOF', got '}' at position 7: 2] fi }̲ echo -n "Addin…(addem 10 15) echo $value [[email protected] ~]# sh s8.sh Adding 10 and 15:25

由於函式使用特殊引數環境變數作為自己的引數值,因此它無法直接獲取指令碼在命令列中的引數值

[[email protected] ~]# more s9.sh #!/bin/bash function badfunc1 { echo $[$1+$2] } if [ KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲ -eq 2 ] then …(badfunc1) echo “The result is $value” else echo “Usage:badtest1 a b” fi [[email protected] ~]# sh s9.sh 2 3 s9.sh: line 3: +: syntax error: operand expected (error token is “+”) The result is 儘管函式也使用了$1和$2變數,但它們和指令碼主體中的$1和$2變數並不相同。要在函式中使用這些值,必須在呼叫函式時手動將他們傳過去

[[email protected] ~]# more s10.sh #!/bin/bash function badfunc1 { echo $[$1+$2] } if [ KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲ -eq 2 ] then …(badfunc1 $1 $2) echo “The result is $value” else echo “Usage:badtest1 a b” fi [[email protected] ~]# sh s10.sh 2 3 The result is 5 通過將$1和$2變數傳給函式,他們就能跟其他變數一樣供函式使用了

函式中的變數 shell指令碼程式設計師帶來麻煩的原因之一就是變數的作用域。作用域是變數可見的區域。函式中定義的變數與普通變數的作用域不同 全域性變數 在shell指令碼中任何地方都是有效的變數。在指令碼的主體部分定義了一個全域性變數,那麼可以在函式內讀取它的值。類似的,如果你在函式內定義了一個全域性變數,可以在指令碼的主體部分讀取它的值 預設情況下,你在指令碼中定義的任何變數都是全域性變數,在函式外定義的變數可在函式內正常訪問 [[email protected] ~]# more s11.sh #!/bin/bash function db1 { value=$[ KaTeX parse error: Expected 'EOF', got '}' at position 13: value * 2 ] }̲ read -p "Enter…value" [[email protected] ~]# sh s11.sh Enter a value: 2 The new value is:4

但這樣很危險,尤其是如果在不同指令碼中使用函式的話。要清楚函式中使用了那些變數,包括用來計算非返回值的變數 [[email protected] ~]# more s12.sh #!/bin/bash function func1 { temp=[[value+5] result=[[temp*2] } temp=4 value=6 func1 echo “The result is $result” if [ $temp -gt $value ] then echo “temp is larger” else echo “temp is smaller” fi [[email protected] ~]# sh s12.sh The result is 22 temp is larger

[[email protected] ~]# more s13.sh #!/bin/bash function func1 { func1函式中使用temptemp變數時,並不會影響在指令碼主體中賦給temp變數的值 local temp=[[value+5] result=[[temp*2] } temp=4 value=6 func1 echo “The result is $result” if [ $temp -gt $value ] then echo “temp is larger” else echo “temp is smaller” fi [[email protected] ~]# sh s13.sh The result is 22 temp is smaller

陣列變數和函式 向函式傳陣列引數 如果將陣列變數當作單個傳遞的話,它不會起作用 [[email protected] ~]# more s14.sh #!/bin/bash function testit { echo “The parameters are:[email protected]” thisarray=$1 試圖將該陣列變數作為函式引數,函式只會取陣列變數的第一個值 echo “The received array is KaTeX parse error: Expected 'EOF', got '}' at position 17: …thisarray[*]}" }̲ myarray=(1 2 3…{myarray[*]}” testit $myarray [[email protected] ~]# sh s14.sh The original array is:1 2 3 4 5 The parameters are:1 The received array is 1

解決上個問題。將陣列變數的值分解成單個的值,然後這些值作為函式引數使用。在函式內部,可以將所有的引數重新組合成一個新的變數