1. 程式人生 > >shell指令碼入門詳解及其例項

shell指令碼入門詳解及其例項

一、條件選擇、判斷(if、case)

1.1 if語句用法及例項

當我們在指令碼中遇到需要判斷的時候,我們就可以用if語句來實現。具體的語法如下:

  •   單分支

    if 判斷條件;then

    條件為真的分支程式碼   fi

  •   雙分支

if 判斷條件; then

條件為真的分支程式碼

else

條件為假的分支程式碼

fi

  •   多分支

if 判斷條件1; then

條件為真的分支程式碼 elif 判斷條件2; then

條件為真的分支程式碼 elif 判斷條件3; then

條件為真的分支程式碼

else

以上條件都為假的分支程式碼 fi

在多分支中,系統會逐條判斷你寫入的條件,第一次遇到“真”條件時,執行該分支,而後結束整個if語句。

注意:1、if和fi是成對出現的

2、if語句可以巢狀。

Example:

1)判斷兩個數字的大小

 1 #!/bin/bash
 2 #定義變數
 3 read -p "Please input the first num:" num1
 4 read -p "Please input the second num:" num2
 5 #判斷數字是否符合標準
 6 if [[ $num1 =~ ^[0-9]+$ && $num2 =~ ^[0-9]+$ ]];then
 7 #    判斷兩個數字的大小並輸出判斷結果
 8     if [ $num1 -lt $num2 ];then
 9         echo "The num2 is biger than the num1"
10     elif [ $num1 -eq $num2 ];then
11         echo "Two numbers equal"
12     else 
13         echo "The num1 is biger than the num2"
14     fi
15 else
16     echo "Please enter the correct number"
17 fi
18 
19 #刪除變數
20 unset num1 num2

2)編寫指令碼/root/bin/createuser.sh,實現如下功能:使用一個使用者名稱做為引數,如果指定引數的使用者存在,就顯示其存在,否則新增之;顯示新增的使用者的id號等資訊

 1 #!/bin/bash
 2 #定義變數
 3 read -p "請輸入一個使用者名稱:" name
 4 #判斷使用者名稱是否存在
 5 if  `id $name &> /dev/null`;then
 6 #    若存在,則輸出ID等資訊
 7 echo "使用者存在,使用者的ID資訊為:`id $name`"
 8 else
 9 #    若不存在,則新增使用者,設定密碼為隨機8位,下次登入時提示修改密碼,同時顯示ID等資訊
10 passwd=`cat /dev/urandom |tr -cd [:alpha:] |head -c8`
11 `useradd $name &> /dev/null`
12 `echo "$passwd" | passwd --stdin $name &> /dev/null`
13 echo "使用者名稱:$name 密碼: $passwd" >> user.txt
14 `chage -d 0 $name`
15 echo "使用者已新增,使用者的ID資訊為:`id $name` 密碼為:$passwd"
16 fi
17 
18 #刪除變數
19 unset name passwd

1.2 case用法及例項

當涉及到多個條件匹配的時候,我們用if可能就很麻煩了,這個時候,我們就可以用case來編寫這個指令碼。case的具體語法如下:

case 變數引用 in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

預設分支

;;

esac

注意:1、case每一個分支後,都是以兩個“;”結尾的(最後一個可以省略)

      2、case和esac是成對出現的

Example:

1)編寫一個指令碼,提示使用者輸入資訊,判斷其輸入的是yes或no或其他資訊。

 1 #!/bin/bash
 2 #定義變數
 3 read -p "Yue ma?(yes or no):" ANS 
 4 #把變數中的大寫轉換為小寫
 5 ans=`echo "$ANS" |tr [[:upper:]] [[:lower:]] `
 6 #判斷輸入的資訊是什麼並輸出結果
 7 case $ans in
 8 yes|y)
 9     echo "see you tonight"
10     ;;  
11 no|n)
12     echo "sorry,I have no time"
13     ;;  
14 *)
15     echo "what’s your means?"
16     ;;  
17 esac
18 
19 #刪除變數
20 unset ANS ans

2)編寫指令碼/root/bin/filetype.sh,判斷使用者輸入檔案路徑,顯示其檔案型別(普通,目錄,連結,其它檔案型別)

 1 #!/bin/bash
 2 read -p "請輸入一個檔案路徑:" file
 3 #判斷檔案是否存在
 4 `ls $file &> /dev/null`
 5 #若存在,判斷檔案型別並輸出
 6 if [ $? -eq 0 ];then
 7     style=`ls -ld $file | head -c1`
 8     case $style in
 9     -)  
10         echo "這是一個普通檔案"
11         ;;  
12     d)  
13         echo "這是一個目錄檔案"
14         ;;  
15     l)  
16         echo "這是一個連結檔案"
17         ;;
18     *)
19         echo "這是其他型別檔案"
20         ;;
21     esac
22 #若不存在,提示並退出
23 else
24     echo "該檔案不存在"
25     exit 2
26 fi
27 
28 #刪除變數
29 unset file style

二、迴圈語句

    在我們的指令碼中,肯定也少不了對某一段程式碼重複執行多次的操作,此時,我們就會用到迴圈語句。迴圈語句中,都是有進入條件和退出條件的,迴圈的次數也分為事先已知事先未知(事先已知就是我們知道迴圈的具體次數,事先未知則是指當滿足某一條件就進行迴圈,但是次數是不確定的。)。接下來,我們就來看看關於迴圈語句的用法。

2.1 for迴圈

for迴圈的執行機制是:一次將列表中的元素賦值給“變數名”;每次賦值後即執行一次迴圈體;直到列表中的元素耗盡,迴圈結束。基本的語法有兩種:

1)for 變數名 in 列表 ; do

迴圈體

done

關於列表的生成方法,如下:

①直接給出列表

②整數列表:

(a){start…end}

(b)`seq start end`

③返回列表的命令

    $(COMMAND)

④使用glob萬用字元如:

      *.sh

⑤變數引用

$i,$*

2)for (( exp1; exp2; exp3 )); do

迴圈體

done

  更清晰的可以從下圖中看出:

Example:

1)列印九九乘法表

 1 #!/bin/bash
 2 #判斷i的值是否在1-9
 3 for i in {1..9};do
 4 #   判斷j的值是否在1-$i
 5 for j in `seq 1 $i`;do
 6 #       若在,則列印i*j的值
 7         echo -en "$i*$j = $[$i*$j]\t" 
 8     done
 9     echo
10 done
11 
12 #刪除變數
13 unset i j

2)輸入正整數n,計算1+…+n的和

 1 #!/bin/bash
 2 #定義變數
 3 sum=0
 4 read -p "請輸入一個正整數:" num 
 5 #判斷num是否是正整數
 6 if [[ $num =~ ^[[:digit:]]+$ ]];then
 7 #   若是,當i在1-$num時,輸出sum值
 8     for i in `seq 1 $num`;do
 9         let sum+=$i    
10     done 
11         echo "sum=$sum"
12 #若不是,提示輸出正整數
13 else 
14     echo "請輸入一個正整數!"
15 fi
16 
17 #刪除變數
18 unset i sum num

2.2 while迴圈

while迴圈比for迴圈略複雜一些,具體語法如下:

while CONDITION; do

迴圈體

done

注意:1、進入條件:CONDITION為true;退出條件:CONDITION為false。

      2、CONDITION為迴圈控制條件:進入迴圈之前,先做一次判斷;每一次迴圈之後會再次做判斷;條件為“true”,則執行一次迴圈;知道條件測試狀態為“false”終止迴圈。

      3、CONDITION一般應該有迴圈控制變數;此變數的值會在迴圈體不斷地被修正。

Example:

1)計算100以內所有正奇數之和

 1 #!/bin/bash
 2 #定義變數
 3 i=1
 4 sum=0
 5 #當i<100時,執行下面語句
 6 while [ $i -le 100 ];do
 7 #當i為奇數時,另sum=sum+I,i=i+1
 8     while [ $[i%2] -eq 1 ];do
 9         let sum+=$i
10         let i+=1 
11 done
12 #   當i不為奇數時,i=i+1
13     let i+=1
14 done
15 #輸出結果
16 echo "sum=$sum"
17 
18 #刪除變數
19 unset i sum

2.3 until迴圈

  until迴圈的語法和while的語法類似,但是進入和退出的條件卻剛好相反,所以不常用,只要我們瞭解即可。具體語法如下:

until CONDITION; do

迴圈體

done

注意:1、進入條件:CONDITION為false;退出條件:CONDITION為true。

    2、do和done成對出現。

Example:

1)迴圈輸出1-10

 1 #!/bin/bash
 2 #定義變數
 3 i=1
 4 #當i>10時,退出迴圈
 5 until [ $i -gt 10 ];do
 6 #   輸出i的值,i=i+1
 7     echo $i 
 8     let i+=1
 9 done
10 
11 #刪除變數
12 unset i 

2.4 select迴圈

  select迴圈主要用於建立選單,按數字順序排列的選單項將顯示在標準錯誤上,並顯示PS3提示符,等待使用者輸入。

  使用者輸入選單列表中的某個數字,執行相應的命令。

  使用者輸入被儲存在內建變數REPLY中。

  select的具體語法如下:

select variable in list; do

迴圈體命令

done

注意:①select是個無線迴圈,因此要記住用break命令退出迴圈,或用exit命令終止指令碼。也可以按ctrl+c退出迴圈。

②select經常和case聯合使用。

③與for迴圈類似,可以省略in list,此時使用位置變數。

Example:

1)生成選單,並顯示選中的價錢。

 1 #!/bin/bash
 2 #定義PS3提示符
 3 PS3="Please choose the menu:"
 4 #輸出選單
 5 select menu in yangroutang mifan hulatang jiaozi lamian huimian quit
 6 do
 7 #   判斷選擇
 8     case $REPLY in
 9     1|4)
10         echo "The price is 20"
11         ;;  
12     2|5)
13         echo "The price is 12"
14         ;;  
15     3|6)
16         echo "The price is 10"
17         ;;  
18     7)  
19         break
20         ;;  
21     *)  
22         echo "Choose error"
23         ;;  
24     esac
25 done

2.5 迴圈小補充

2.5.1 迴圈控制語句 continue&break

  迴圈控制語句用於迴圈體中,常見的控制語句有兩種,continue和break。接下來我們就來看看兩者的區別:

continue語句結束的是本輪迴圈,直接進入下一輪判斷;最內層是第1層。

break語句結束的則是整個迴圈,最內層為第1層。

Example:

1)求(1+3+…+49+53+…+99)的和

 1 #定義變數
 2 sum=0
 3 for ((i=1;i<=100;i++));do
 4 #   當i為奇數時,繼續執行
 5     if [ $[i%2] -eq 1 ];then
 6 #       當i=51時,跳過該迴圈
 7         if [ $i -eq 51 ];then
 8             continue
 9         fi  
10         let sum+=$i
11     fi  
12 done
13 echo "sum=$sum"
14 
15 #刪除變數
16 unset i sum

2)求(1+3+…+49)的和

 1 #!/bin/bash
 2 #定義變數
 3 sum=0
 4 for ((i=1;i<=100;i++));do
 5 #   當i為奇數時,繼續執行
 6     if [ $[i%2] -eq 1 ];then
 7 #       當i=51時,跳出整個迴圈
 8         if [ $i -eq 51 ];then
 9             continue
10         fi  
11         let sum+=$i
12     fi  
13 done
14 echo "sum=$sum"
15 
16 #刪除變數
17 unset i sum

2.5.2 迴圈控制命令shift

  位置引數可以用shift命令左移,比如shift 3表示原來的$4現在變成$1,原來的$5現在變成$2等等,原來的$1,$2,$3丟棄,$0不移動。不帶引數的shift命令相當於shift 1。

  我們知道,對於位置變數或命令列引數,其個數必須是確定的,或者當shell程式不知道其個數時可以把所有引數一起賦值給變數$*。當用戶要求shell在不知道位置變數個數的情況下,還能逐個的把引數一一進行處理,也就是在$1後為$2等。在shift命令執行前變數$1的值在shift命令執行後就不可用了。

Example:

1)測試shift命令

1 #!/bin/bash
2 until [ $# -eq 0 ];do
3     echo "The first argument is:$1,The number of arguments is:$#"
4     shift
5 done

2.5.3 訊號捕捉trap

  trap是一個shell內建命令,它用來在指令碼中指定訊號如何處理。比如,按Ctrl+C會使指令碼終止執行,實際上系統傳送了SIGINT訊號給指令碼程序,SIGINT訊號的預設處理方式就是退出程式。如果要在Ctrl+C不退出程式,那麼就得使用trap命令來指定一下SIGINT的處理方式了。trap命令不僅僅處理Linux訊號,還能對指令碼退出(EXIT)、除錯(DEBUG)、錯誤(ERR)、返回(RETURN)等情況指定處理方式。

  基本格式語法如下:

  •   trap ‘觸發指令’ 訊號

  自定義程序收到系統發出的指定訊號後,將執行觸發指令,而不是執行原操作

  •       trap ‘’ 訊號

  忽略訊號的操作

  •   trap ‘-’ 訊號

  恢復原訊號的操作

  •       trap -p

  列出自定義訊號的操作,即提示當前使用的trap操作是什麼。

注意:①訊號的表示方法:可以是完整訊號/簡寫/數字(具體內容通過kill -l查詢)

②訊號9,強制殺死,捕獲不到。

Example:

1)列印0-9,ctrl+c終止無效

1 #!/bin/bash
2 #設定訊號捕獲
3 trap 'echo press ctrl+c' 2
4 for ((i=0;i<10;i++));do
5     sleep 1
6     echo $i
7 done

2)列印0-9,3之前ctrl+c不能終止,3之後恢復,能終止

 1 #!/bin/bash
 2 #設定訊號捕獲
 3 trap '' 2
 4 trap -p
 5 for ((i=0;i<3;i++));do
 6     sleep 1
 7     echo $i
 8 done
 9 trap '-' SIGINT
10 for ((i=3;i<10;i++));do
11     sleep 1
12     echo $i
13 done

2.5.4 建立無限迴圈

  在我們的shell指令碼中,可以建立一個死迴圈,具體設定如下:

  while true;do

迴圈體

  done

2.5.5 在迴圈語句中執行並行命令

  當我們需要在腳本里執行一條命令很多次的時候,我們可以將其設定為並行執行,這樣可以極大的提升指令碼執行速度,但是也有缺點,並行執行的話,相當於開了很多子shell一起執行,執行速度上來了,但是對資源的消耗也增多了

  具體的用法示例如下:

  for name in 列表; do

    {

迴圈體

}$

  done

  wait

Example:

1)搜尋自己指定的的IP(子網掩碼為24的)的網段中,up的ip地址

 1 #!/bin/bash
 2 #定義變數
 3 read -p "Please input network (eg:172.17.0.1): " net echo $net |egrep -o "\<(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"
 4 #判斷網段是否符合規範
 5 [ $? -eq 0 ] || ( echo "input error";exit 10 )
 6 #判斷網段內哪些IP能ping通,並行執行
 7 IP=`echo $net |egrep -o "^([0-9]{1,3}\.){3}"`
 8 for i in {1..254};do
 9      {   
10          ping -c 1 -w 1 $IP$i &> /dev/null && \
11          echo "$IP$i is up" 
12      }&  
13 done
14 wait
15  
16 #刪除變數
17 unset net IP i

三、小補充

      介紹了這麼多語法,我們來玩一些好玩的吧~下面是小編給大家分享的幾個有意思的指令碼

1)列印等腰三角形(帶閃爍)

 1 #!/bin/bash
 2 #num=總行號  i=第幾行  j=*個數  k=空格個數
 3 read -p "請輸入一個數字:" num 
 4 for i in `seq 1 $num`;do
 5     for k in `seq 1 $[$num-$i]`; do
 6         echo -n " "
 7     done
 8     for j in `seq 1 $[2*$i-1]`;do
 9         if [ $j -eq 1 ] || [ $j -eq $[2*$i-1] ] || [ $i -eq $num ];then
10             color=$[RANDOM%5+31]
11             echo -en "\033[1;$color;5m*\033[0m"
12         else
13             echo -n "*"
14         fi  
15     done
16     echo
17 done
18 
19 #刪除變數
20 unset num i j k color

具體的效果大家可以自己去嘗試,就是下面兩張圖配合出來的效果:

2)列印國際象棋棋盤

 1 #!/bin/bash
 2 #定義變數
 3 color_1="\033[1;44m  \033[0m"
 4 color_2="\033[1;45m  \033[0m"
 5 for (( i=1;$i <=8;i++ ));do
 6     for (( j=1;$j <=8;j++ ));do
 7         if [ $[$i%2] == 1 ] && [ $[$j%2] == 1 ];then
 8             echo -en "$color_1$color_2"
 9         elif [ $[$i%2] == 0 ] && [ $[$j%2] == 0 ];then
10             echo -en "$color_2$color_1"
11         fi  
12     done
13     echo
14 done
15 
16 #刪除變數
17 unset color_1 color_2 i j