shell淺談之三for、while、until迴圈
一、簡介
Shell程式設計中迴圈命令用於特定條件下決定某些語句重複執行的控制方式,有三種常用的迴圈語句:for、while和until。while迴圈和for迴圈屬於“當型迴圈”,而until屬於“直到型迴圈”。迴圈控制符:break和continue控制流程轉向。
二、詳解
1、for迴圈
(1)for迴圈有三種結構:一種是列表for迴圈,第二種是不帶列表for迴圈。第三種是類C風格的for迴圈。
(2)列表for迴圈
#!/bin/bash for varible1 in {1..5} #for varible1 in 1 2 3 4 5 do echo "Hello, Welcome $varible1 times " done
- do和done之間的命令稱為迴圈體,執行次數和list列表中常數或字串的個數相同。for迴圈,首先將in後list列表的第一個常數或字串賦值給迴圈變數,然後執行迴圈體,以此執行list,最後執行done命令後的命令序列。
- Sheel支援列表for迴圈使用略寫的計數方式,1~5的範圍用{1..5}表示(大括號不能去掉,否則會當作一個字串處理)。
- Sheel中還支援按規定的步數進行跳躍的方式實現列表for迴圈,例如計算1~100內所有的奇數之和。
通過i的按步數2不斷遞增,計算sum值為2500。同樣可以使用seq命令實現按2遞增來計算1~100內的所有奇數之和,for i in $(seq 1 2 100),seq表示起始數為1,跳躍的步數為2,結束條件值為100。#!/bin/bash sum=0 for i in {1..100..2} do let "sum+=i" done echo "sum=$sum"
- for迴圈對字串進行操作,例如通過for迴圈顯示當前目錄下所有的檔案。
#!/bin/bash
for file in $( ls )
#for file in *
do
echo "file: $file"
done
也可一使用for file in *,萬用字元*產生檔名擴充套件,匹配當前目錄下的所有檔案。
- for通過命令列來傳遞指令碼中for迴圈列表引數
#!/bin/bash
echo "number of arguments is $#"
echo "What you input is: "
for argument in " [email protected]"
do
echo "$argument"
done
$#表示引數的個數,[email protected]表示引數列表而$*則把所有的引數當作一個字串顯示。
(3)不帶列表for迴圈
由使用者制定引數和引數的個數,與上述的for迴圈列表引數功能相同。
#!/bin/bash
echo "number of arguments is $#"
echo "What you input is: "
for argument
do
echo "$argument"
done
比上述程式碼少了[email protected]引數列表,$*引數字串。
(4)類C風格的for迴圈
也被稱為計次迴圈
#!/bin/bash
for((integer = 1; integer <= 5; integer++))
do
echo "$integer"
done
for中第一個表示式(integer = 1)是迴圈變數賦初值的語句,第二個表示式(integer <= 5)決定是否進行迴圈的表示式,退出狀態為非0時將退出for迴圈執行done後的命令(與C中的for迴圈條件是剛好相反的)。第三個表示式(integer++)用於改變迴圈變數的語句。
Sheel中不執行使用非整數型別的數作為迴圈變數,迴圈條件被忽略則預設的退出狀態是0,for((;;))為死迴圈。
類C的for迴圈計算1~100內所有的奇數之和。
#!/bin/bash
sum=0
for(( i = 1; i <= 100; i = i + 2 ))
do
let "sum += i"
done
echo "sum=$sum"
2、while迴圈
也稱為前測試迴圈語句,重複次數是利用一個條件來控制是否繼續重複執行這個語句。為了避免死迴圈,必須保證迴圈體中包含迴圈出口條件即表示式存在退出狀態為非0的情況。
(1)計數器控制的while迴圈
#!/bin/bash
sum=0
i=1
while(( i <= 100 ))
do
let "sum+=i"
let "i += 2"
done
echo "sum=$sum"
指定了迴圈的次數500,初始化計數器值為1,不斷測試迴圈條件i是否小於等於100。在迴圈條件中設定了計數器加2來計算1~100內所有的奇數之和。(2)結束標記控制的while迴圈
設定一個特殊的資料值(結束標記)來結束while迴圈。
#!/bin/bash
echo "Please input the num(1-10) "
read num
while [[ "$num" != 4 ]]
do
if [ "$num" -lt 4 ]
then
echo "Too small. Try again!"
read num
elif [ "$num" -gt 4 ]
then
echo "To high. Try again"
read num
else
exit 0
fi
done
echo "Congratulation, you are right! "
例:通過結束標記控制實現階乘的操作
#!/bin/bash
echo "Please input the num "
read num
factorial=1
while [ "$num" -gt 0 ]
do
let "factorial= factorial*num"
let "num--"
done
echo "The factorial is $factorial"
(3)標誌控制的while迴圈
使用使用者輸入的標誌值來控制迴圈的結束(避免不知道迴圈結束標誌的條件)。
#!/bin/bash
echo "Please input the num "
read num
sum=0
i=1
signal=0
while [[ "$signal" -ne 1 ]]
do
if [ "$i" -eq "$num" ]
then
let "signal=1"
let "sum+=i"
echo "1+2+...+$num=$sum"
else
let "sum=sum+i"
let "i++"
fi
done
標誌控制的while迴圈求1~n的累加和,迴圈變數值小於100執行else累加同時迴圈變數加1,直到迴圈變數值等於100將標誌值設定為1,並輸出。
標誌控制的while迴圈與結束標記控制的while迴圈的區別是使用者無法確定無法確定結束標誌,只能程式執行後確定結束標誌。兩者也可以相互轉化。
(4)命令列控制的while迴圈
使用命令列來指定輸出引數和引數個數,通常與shift結合使用,shift命令使位置變數下移一位($2代替$1、$3代替$2,並使$#變數遞減),當最後一個引數顯示給使用者,$#會等於0,$*也等於空。
#!/bin/bash
echo "number of arguments is $#"
echo "What you input is: "
while [[ "$*" != "" ]]
do
echo "$1"
shift
done
迴圈條件可以改寫為while[[ "$#" -ne 0 ]],等於0時退出while迴圈
3、until迴圈
until命令和while命令類似,while能實現的指令碼until同樣也可以實現,但區別是until迴圈的退出狀態是不為0,退出狀態是為0(與while剛好相反),即whie迴圈在條件為真時繼續執行迴圈而until則在條件為假時執行迴圈。
#!/bin/bash
i=0
until [[ "$i" -gt 5 ]] #大於5
do
let "square=i*i"
echo "$i * $i = $square"
let "i++"
done
4、迴圈巢狀
一個迴圈體內又包含另一個完整的迴圈結構,在外部迴圈的每次執行過程中都會觸發內部迴圈,for、while、until可以相互巢狀。
(1)巢狀迴圈實現九九乘法表
#!/bin/bash
for (( i = 1; i <=9; i++ ))
do
for (( j=1; j <= i; j++ ))
do
let "temp = i * j"
echo -n "$i*$j=$temp "
done
echo "" #output newline
done
(2)for迴圈巢狀實現*圖案排列
#!/bin/bash
for ((i=1; i <= 9; i++))
do
j=9;
while ((j > i))
do
echo -n " "
let "j--"
done
k=1
while ((k <= i))
do
echo -n "*"
let "k++"
done
echo ""
done
外層for迴圈嵌套了兩個內層while迴圈,先列印空格在列印*號形成圖案。
5、迴圈控制符break和continue
若須退出迴圈可使用break迴圈控制符,若退出本次迴圈執行後繼續迴圈可使用continue迴圈控制符。
(1)break
在for、while和until迴圈中break可強行退出迴圈,break語句僅能退出當前的迴圈,如果是兩層迴圈巢狀,則需要在外層迴圈中使用break。
#!/bin/bash
sum=0
for (( i=1; i <= 100; i++))
do
let "sum+=i"
if [ "$sum" -gt 1000 ]
then
echo "1+2+...+$i=$sum"
break
fi
done
(2)continue
在for、while和until中用於讓指令碼跳過其後面的語句,執行下一次迴圈。continue用於顯示100內能被7整除的數。
#!/bin/bash
m=1
for (( i=1; i < 100; i++ ))
do
let "temp1=i%7" #被7整除
if [ "$temp1" -ne 0 ]
then
continue
fi
echo -n "$i "
let "temp2=m%7" #7個數字換一行
if [ "$temp2" -eq 0 ]
then
echo ""
fi
let "m++"
done
6、select結構
select結構從技術角度看不能算是迴圈結構,只是相似而已,它是bash的擴充套件結構用於互動式選單顯示,功能類似於case結構比case的互動性要好。
(1)select帶引數列表
#!/bin/bash
echo "What is your favourite color? "
select color in "red" "blue" "green" "white" "black"
do
break
done
echo "You have selected $color"
(2)select不帶引數列表
該結構通過命令列來傳遞引數列表,由使用者自己設定引數列表。
#!/bin/bash
echo "What is your favourite color? "
select color
do
break
done
echo "You have selected $color"
三、總結
(1)迴圈結構中相互巢狀組成更復雜的流程,並結合break和continue可以實現很多複雜的運算。
(2)可以結合其他語言的語法有助於更好的理解迴圈結構。
(3)熟練應用還需要大量的重複練習,重寫優秀的shell程式碼也是一種很好的方式。