1. 程式人生 > >9.Linux的程式化指令碼(Shell Scripts)

9.Linux的程式化指令碼(Shell Scripts)

目錄

1.什麼是 Shell scripts?

是利用 shell 的功能所寫的一個『程式 (program)』,這個程式是使用純文字檔案,將一些 shell 的語法與指令(含外部指令)寫在裡面, 搭配正規表示法、管線命令與資料流重導向等功能,以達到我們所想要的處理目的,簡單的說, shell script 就像是早期 DOS 年代的批處理檔案 (.bat) ,最簡單的功能就是將諸多指令彙整寫在一起, 使使用者很輕易的就能夠一個按鍵的方法去處理複雜的動作 (執行一個檔案"shell script" ,就能夠一次執行多個指令),shell script 可以簡單的被看成是批處理檔案, 也可以被說成是一個程式語言,且這個程式語言由於都是利用 shell 與相關工具指令, 所以不需要編譯即可執行,且擁有不錯的排錯 (debug) 工具,以,他可以幫助系統管理員快速的管理好主機。

2.執行shell scripts的一些規則

1. 指令的執行是從上而下、從左而右的分析與執行; 2.  指令、選項與引數間的多個空白都會被忽略掉; 3. 空白行也將被忽略掉,而且 [tab] 按鍵所推開的空白同樣視為空格鍵; 4. 如果讀取到一個 Enter 符號 (CR) ,就嘗試開始執行該行 (或該串) 命令; 5. 如果如果一行的內容太多,則可以使用『 \[Enter] 』來延伸至下一行; 6. 『 # 』可做為批註!任何加在 # 後面的資料將全部被規為批註文字而被忽略,不會作為程式執行!

  • 如何去執行一個指令碼程式

假如在/home/test目錄下,有一個指令碼程式bash.sh,如何執行呢?

o  絕對路徑:使用 /home/test/bash.sh 來下達指令; o  相對路徑:假設工作目錄在 /home/test/ ,則使用 ./bash.sh 來執行 o  變數『PATH』功能:將 shell.sh 放在 PATH 指定的目錄內,例如: ~/test/

3.編寫簡單的script

注意事項:

1.第一行 #!/bin/bash 在宣告這個 script 使用的 shell 名稱,系統才知道是用哪個shell去解析這些命令,而這裡指定的是bash.

2.除了第一行,其他如果開頭以#開頭,都是代表註釋。

3.良好的寫程式習慣能提高你的工作效率,比如一個指令碼除了程式應該還有其他的命令,比如:1. 內容與不功能; 2. 版本資訊; 3. 作者不聯絢方式; 4. 建檔日期;5. 歷史紀錄 等等。

例子:

寫一個簡單的指令碼,顯示第一部分顯示日期,第二部分顯示日曆,那麼需要用到兩個命令,那就是date,和cal。

在、/test下新建一個檔案,命令為shell01.sh,使用vim編輯器編輯如下:

編輯內容如下:

寫好指令碼後退出,可以看一下,shell01.sh的許可權:

給這個檔案加上可執行許可權:使用命令:chmod +x shell01.sh

通過上面知道,我們可以有三個方法去執行這個指令碼:

第一種:使用相對路徑,直接在工作目錄下執行

使用命令:./shell01.sh

第二種:使工作目錄回到家目錄,需要使用絕對路徑。

使用命令:~/test/shell01.sh

第三種:修改環境變數PATH,把路徑:~/test/ 加到環境變數上

無論在哪個工作目錄下,現在直接使用命令:shell01.sh

4.數值運算:簡單的加減乘除

我們可以使用declare來定義變數的型別, 當變數定義成為整數後才能進行加減運算啊!此外,我們也可以利用『 $((計算式)) 』來進行數值運算。

例子1:使用declare把變數定義成整形進行加法的運算:

例子2:直接使用let進行數值運算:

可以使用"(())"這樣兩對括號代替let進行數值運算:

5.善用判斷式 

重點:$?(指令返回值),&& 或 || 

  • $?:就像一個容器一樣,傳回執行指令是否正確的結果,它只會記錄上一次命令執行的結果,如果上一次執行的結果是正確的話此值就是:0,如果上一次執行結果是錯的話就是:非0

例子:

執行命令:cal,肯定是正確的結果,返回0,再次執行:aaa,錯誤,返回0:。

  •  && 或 ||

這兩個符號也可以和多條命令結合一起執行,用&& 或者 || 符號分開,但是他們的含義不一樣。如下表所示:

註釋:cmd1代表一條指令,cmd2代表另一條指令

指令 說明
cmd1 && cmd2

1.如果cmd1執行的結果是正確的,則執行cmd2

2.如果cmd1執行結果是錯誤的,則不執行cmd2

註釋:其實就是判斷 cmd1和cmd2與的結果是否正確,如果第一個錯了的話,與的結果肯定為錯,沒必要執行第二個了。

cmd1  || cmd2

1.如果cmd1執行結果是正確的,則不執行cmd2

2.如果cmd1執行結果是錯誤的,則執行cmd2

註釋:兩個數值進行或運算,只要有一個是正確的結果就是正確,如果第一個正確就沒有必要去驗證後面那個了,原理一樣。

例子1:

使用命令: cal && echo OK 

解釋:命令1是正確的,那就執行命令2

例子2:

使用命令:aaaa && echo OK

提示: || 符號的邏輯是一樣的。

5.1.利用 test 指令的測試功能

  • 關於某個檔名的『檔案型別』判斷,如 test -e filename 表示存在否
測試標誌 含義
-e 該“檔名”是否存在?
-f 該“檔名”是否在且為檔案(file)?
-d 該“檔名”是否尋在且為目錄(directory)?
-b 該“檔名”是否尋在且為一個block device裝置?
-c 該“檔名”是否存在且為一個character devicce 裝置?
-S 該“檔名”是否存在且為一個Socket檔案?
-p 該“檔名”是否存在且為一個FIFO(pipe)檔案?
-L 該“檔名”是否存在且為一個連結檔案?
  •  關於檔案的許可權偵測,如 test -r filename 表示可讀否 (但 root 許可權常有例外)
測試標誌 含義
-r 偵測該檔名是否存在且具有“可讀”的許可權?
-w 偵測該檔名是否存在且具有“可寫”的許可權?
-x 偵測該檔名是否存在且具有“可執行”的許可權?
-u 偵測該檔名是否存在且具有“SUID”的屬性?
-g 偵測該檔名是否存在且具有“SGID”的屬性?
-k 偵測該檔名是否存在且具有“Sticky bit”的屬性?
-s 偵測該檔名是否存在且具為“非空白檔案”?
  • 兩個檔案之間的比較,如: test file1 -nt file2
測試標誌 含義
-nt (newer than)判斷file1是否比file2新
-ot (older than)判斷file1是否比file2舊
-ef 判斷file1 與 file2 是否為同一個檔案,可用在判斷hard link 的判定上,主要意義在判斷,兩個檔案是否均指向同一個inode.
  • 關於兩個整數之間的判定,例如 test n1 -eq n2
測試標誌 含義
-eq 兩數值相等(equal)
-ne 兩數值不等(not equal)
-gt n1 大於n2(greater than)
-lt n1 小於 n2 (less than)
-ge n1 大於等於 n2(greater than or equal)
-le n1 小於等於n2(less than or equal)
  • 判定字串的資料
測試標誌 含義
test -z string 判定字串是否為0?若string為空字串,則為true
test -n string

判定字串是否為非0?若string為空字串,則為false

注意:-n 可以省略

test  str1  = str2 判定str1是否等於str2,若相等,則傳回 true
test str1  != str2 判定str1 是否不等於str2,若相等,則傳回false
  • 多重條件判定,例如:test -r filename -a -x filename
測試標誌 含義
-a (and)兩種狀況同時成立,例如:test -r file -x file ,則file同時具有r與x許可權時,才回傳true
-o (or)兩狀態任何一個成立,例如:test -r file -o -x file ,則file具有r或者x許可權時,就會傳回true
! 相反狀態,如:test! -x file ,當file不具有x時,返回ture

例子1:

建立兩個變數,然後判斷兩個變數的值是否相等

例子2:利用中括號“[ ]”代替test

6.條件判斷式

6.1.利用 if .... then

語法:

if [ 條件判斷式 ]; then             當條件判斷式成立時,可以進行的指令工作內容;

elif [ 條件判斷式 ]; then             當條件判斷式成立時,可以進行的指令工作內容;

elif [ 條件判斷式 ]; then

當條件判斷式成立時,可以進行的指令工作內容;

                  .

                  .

 else            當條件判斷式成立時,可以進行的指令工作內容;fi      <==將 if 反過來寫,結束 if 的意思!

例子1:

我們知道、/etc下的passwd檔案存放在我們的使用者密碼等資訊,而且第一項開始就是使用者名稱,如果我們想測試一個使用者是否存在的話可以通過檢視這個使用者名稱是否存在來判定,通過位置變數傳遞一個引數,然後通過grep提取開頭有我們所輸入使用者名稱的行,那麼這個使用者就存在,否則不存在這個使用者。

新建一個指令碼檔案,命名為:sh02.sh

執行指令碼:

提示:如果不想顯示提取出來的結果,給grep加上一個-q選項。

例子2:

讓使用者輸入一個年齡,然後根據年齡判定現在所處的階段,比如小孩,年輕人...

新建一個指令碼程式,命名為:sh03.sh

程式碼如下:

#!/bin/bash
read -p "Please enter your age: " name
if [ "$name" -le 0 ] || [ "$name" -ge 150 ]; then
        echo "Sorry,Please enter a correct age!"
elif [ "$name"  -gt 0 ] && [ "$name" -le 20 ]; then
        echo "hello,kids!"
elif [ "$name"  -gt 20 ] && [ "$name" -le 50 ]; then
        echo "hello,adults!"
else
        echo "hello,senior citizens!"
fi

執行這個指令碼程式:

技巧:在指令碼中加入set命令進行排錯。

6.2.利用 case ..... esac 判斷

語法:

case  $變數名稱 in                                 <==關鍵詞為 case ,注意變數前的$符號         "第一個變數內容")                          <==每個變數內容建議用雙引號括起來,關鍵詞則為小括號 )                     程式段                     ;;                                        <==每個類刪結尾使用兩個連續的分號來處理!          "第二個變數內容")                     程式段                      ;;*)                                                              <==最後一個變數內容都會用 * 來代表所有其他值不包括第一個變數內容與第二個                                                                         變數內容的其他程式執行段。                    exit 1                    ;;esac                                                          <==最終的 case 結尾。

例子1:

使用位置變數輸入一個值,然後通過case判斷這個字串,然後輸出相對應結果:

新建一個指令碼,命名為:sh04.sh

程式碼如下:

#!/bin/bash
case $1 in
        [Aa]lice)
                echo "my name is Alice!"
                ;;
        bob)
                echo "my name is bob"
                ;;
        tom)    echo "my name is tom"
                ;;
        *)
                echo "i don't know who i am!"
esac

執行指令碼:

例子2:

新建一個指令碼,然後根據輸入的數字來顯示名字:

命名為:sh05.sh

程式碼如下:

#!/bin/bash
cat <<END
        1) Alice
        2) tom
        3) bob
        4) Jude
END
read -p "Please enter a number: " num
case $num in
        1)
                echo Alice
                ;;
        2)
                echo tom
                ;;
        3)      echo bob
                ;;
        4)      echo Jude
                ;;
        *)
                echo "!!!!error!!!!"
esac

執行指令碼:

6.3.利用 function 功能 

功能:簡單的說,其實, 函式可以在 shell script 當中做出一個類似自定義執行指令的東西,最大的功能是, 可以簡化我們很多的程式程式碼,使用函式幫我們把重複執行的使用一個函式的功能打包起來,然後需要使用的時候,只需要呼叫這個函式就可以了。

語法:

function 函式名() {             程式段 }

提示:function也可以省略。

例子:

新建一個指令碼,命名為:sh06.sh

程式碼如下:

#!/bin/bash
function test(){
        echo this is a test function.
        echo hello world!

}
echo "*************first test ****************"
test
echo "*************second test ***************"
test

執行指令碼:

6.3.迴圈 (loop)

6.3.1.while do done, until do done (不定迴圈)

語法:

while [ condition ]                     <==中括號內的狀態就是判斷式do                                             <==do 是迴圈的開始!             程式段落done                                         <==done 是迴圈的結束

注意:while 的中文是『當....時』,所以,這種方式說的是『當 condition 條件成立時,就進行迴圈,直到condition 的條件不成立才停止』的意思。

語法:

until [ condition ]do              程式段落done

注意:和while相反,當condition條件成立時,就結束執行,否則一直執行。

例子1:

新建一個指令碼檔案,命名為:sh07.sh,定義一個變數sum等於,當sum小於0的話,就開始迴圈自增,直到sum的值大於或者等於10,才停止自增。

#!/bin/bash
sum=0
while [ "$sum" -lt 10 ]
do
        let sum+=1
        echo $sum
done  

執行指令碼:

例子2:

模擬輸入登入密碼的選項,需要你輸入密碼,如果密碼輸入不對就重複輸入:

新建一個指令碼,命名為:sh08.sh

程式碼如下:

#!/bin/bash
try=3
read -p "Please enter your passwd: " mypasswd
while [ "$mypasswd" != 123456 ] && [ "$try" -gt 0 ]
do
        echo "Error!!!  Try again."
        read -p "Try again,left "$try" times: "
        let try-=1;

done
~    

執行指令碼:

6.3.2.for...do...done (固定迴圈)

語法:

for var in con1 con2 con3 ...do            程式段done

以上面的例子來說,這個 $var 的髮量內容在迴圈工作時: 1. 第一次迴圈時, $var 的內容為 con1 ; 2. 第二次迴圈時, $var 的內容為 con2 ; 3. 第三次迴圈時, $var 的內容為 con3 ; 4. ....

例子1:

我們可以做個簡單的練習。假設我有三種動物,分別是 dog, cat, elephant 三種, 我想每一行都輸出這樣:『There are dogs...』之類的字樣,則可以如下程式碼:

新建一個指令碼檔案,命名為:sh09.sh

#!/bin/bash
for animal in dog cat elephant
do
        echo "There are ${animal}s...."
done 

執行指令碼,執行三次迴圈:

例子:

列印:a1-a5,b1-b5,c1-c5,d1-d5

兩重for迴圈,不使用指令碼直接在螢幕上寫for語句:

 

6.3.3.for...do...done 的數值處理

語法:

for (( 初始值; 限制值; 執行步階 ))do           程式段done

  初始值:某個變數在迴圈當中的起始值,直接以類似 i=1 設定好;   限制值:當變數的值在這個限制刢值的範圍內,就繼續進行迴圈。例如 i<=100;   執行步階:每作一次迴圈時,變數值改變。例如 i=i+1。

例子:新建一個指令碼程式,命名為:sh10.sh.程式讓使用者輸入一個值,然後從1開始加到這個值,最後列印結果,例如輸入10:就從1+2+3...+10;的結果打印出來,程式如下:

#!/bin/bash
sum=0
read -p "Please enter a number: " num
for((i=1;i<=$num;i++))
do

        sum=$(($sum+$i))
done
echo "The result is : $sum"

執行指令碼: