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
 

 

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章