shell 腳本編程之循環語句

for 循環

帶列表的 for 循環

for VAR in list
do
    command
done

for 循環會遍歷列表的每一項,逐項賦給變量 VAR,然後對變量 VAR 進行操作。shell 的列表很隨意,幾個項之間用空格隔開就是一個列表,如 for var in a b c 遍歷的就是列表 {a b c},for var in 1 2 3 遍歷的就是列表 {1 2 3}。
關於數字列表可以使用 {start..end} 來表示一個順序列表,也可以使用 seq 命令來生成,語法是 seq start step end,step 可省略。

#learn_loop_for.sh
#!/bin/bash
for fruit in apple banana pear orange
do
    echo $fruit is my favoriate
done

for i in {1..5}
do
    echo -n "$i " 
done

echo

for i in $(seq 1 2 10)
do
    echo -n "$i "
done

執行結果

apple is my favoriate
banana is my favoriate
pear is my favoriate
orange is my favoriate
1 2 3 4 5
1 3 5 7 9

不帶列表的 for 循環

for VAR
do
    command
done

不帶列表的 for 循環就是省略了後面的列表,但其實還是有列表的,這個列表就是腳本的參數列表。也就是說上面的結構等價於

for VAR in $@ #或 $*
do
    command
done

類 C 的 for 循環

for ((expression1;expression2;expression3))
do
    command
done

這種 for 循環與 c 語言特別相似,不同的是 for 後面要用兩對括號。

#!/bin/bash
for((i=1,j=100;i<5;i++,j--))
do
    echo "$i $j"
done

執行結果

1 100
2 99
3 98
4 97

while 循環

while expression
do
    command
done

while 循環當 expression 爲真時會一直執行循環體,直到 expression 爲假時跳出循環。

until 循環

until expression
do
    command
done

until 循環和 while 循環剛好相反,當 expression 爲真時立即跳出循環,否則一直執行循環體直到條件爲真。

select 循環

select VAR in list
do
    command
done

select 列表的結構和 for 有點相似,也是遍歷一個列表。select 循環是一種菜單擴展循環,它會把列表的所有項取出來並用序號 1,2,3 來標明輸出,然後等待用戶選擇序號。select 循環不會自動跳出循環,必須使用 break 或 exit 等命令退出。

#!/bin/bash
echo please select a day
days="Mon Tue Wed Thr Fri Sat Sun"
select day in $days
do
    case $day in
        Mon) echo Today is Monday ;;
        Tue) echo Today is Tuesday ;;
        Wed) echo Today is Wednesday ;;
        Thr) echo Today is Thursday ;;
        Fri) echo Today is Friday ;;
        Sat|Sun) echo Today is rest day ;;
        *) echo unknown select and now exit && break ;;
    esac
done

執行結果

please select a day
1) Mon
2) Tue
3) Wed
4) Thr
5) Fri
6) Sat
7) Sun
#? 1
Today is Monday
#? 6
Today is rest day
#?
1) Mon
2) Tue
3) Wed
4) Thr
5) Fri
6) Sat
7) Sun
#? 5
Today is Friday
#? 0
unknown select and now exit

select 循環將列表項按 1-7 的編號打印出來,然後等待用戶選擇,如果用戶沒選擇任何一個序號就直接按回車,shell 將再次打印出列表項。當輸入 1-7 之外的內容,case 判斷將進入 default 分支,break 語句用於跳出循環,注意 case 語句並不需要 break 語句,這和 c 語言很不一樣。

break && continue

break 和 continue 的意義和 c 語言一樣,break 用於結束整個循環,continue 用於跳過本次循環。但 shell 的 break 和 continue 有一個很強大的地方就是可以帶上一個數字,表示作用於哪一層循環。默認不帶數字表示作用於 break 或 continue 所在的那一層循環。break 2 表示直接跳出 break 外面的那一層循環。
下面實現一個求 100 以內所有素數的腳本

#!/bin/bash
for((i=2;i<=100;i++))
do
    j=2
    for((;j<i;j++))
    do
        if ! (($i%$j)); then
            break
        fi
    done
    if (($j==$i)); then
        echo -n "$i "
    fi
done

執行結果

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

這是 c 語言的一般做法,內層循環判斷 i 能否被 2-i 之間的數整除,如果找到能整除的數,則跳出內層循環;在內層循環之後判斷 j 的值,如果小於 i 說明內層循環提前被 break 掉,也就是有可以整除的數,因此 i 不是素數。但在 shell 中還有另一種寫法

#!/bin/bash
for((i=2;i<=100;i++))
do
    for((j=2;j<i;j++))
    do
        if (($i%$j==0)); then
            continue 2
        fi
    done
    echo -n "$i "
done

這個腳本的關鍵在 continue 2 這個語句,當內層循環找到可以整除的數時,不是 break 掉內層循環,而是跳過外層循環,所以內層循環剩下的遍歷和內層循環之後的操作都會被跳過。

”死循環“

for((;1;)
do
    command
done

判定條件不一定是 1,只要是非 0 的數字都表示真。

while ((1))
do
    command
done
while true
do
    command
done
while :
do
    command
done

同樣,第一種寫法的判定條件不一定要是 1,只要是非 0 的數字都表示真。

until ((0))
do
    command
done
until false
do
    command
done

第一種寫法的判定條件必須是 0,其它非 0 的數字都表示真,會馬上結束循環。

嵌套循環

嵌套循環其實沒什麼好講的,前面已經用過了。這裏再提一下,每種循環都可以嵌套,不同的循環結構也可以相互嵌套;下面用兩層循環實現一個九九乘法表

#!/bin/bash
i=1
while (($i<10))
do
    for j in `seq 1 $i`
    do
        echo -n "$i*$j=$[$i*$j] "
    done
    echo
    let "i++"
done

這個腳本外層循環使用 while 結構,內層循環使用 for 列表結構,這其實不是一種好的寫法,只是爲了測試不同的循環結構可以相互嵌套。一個好的寫法如下

#!/bin/bash
for((i=1;i<=9;i++))
do
    for((j=1;j<=i;j++))
    do
        echo -n "$i*$j=$[$i*$j] "
    done
    echo
done

執行結果

1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

“真” & “假”

條件語句和循環語句經常需要判斷條件的真假,這裏再總結一下 shell 中的“真”和“假”。

  • 第一種,使用字符串 true 表示真,false 表示假
    這種方式直接使用字符串直接量來表示,只能是 true 或者 false 這兩個直接量,如果使用其它字符串,命令將報錯
#!/bin/bash
if true; then
    echo doing
fi
if "true"; then
    echo doing
fi
if "other"; then
    echo doing
fi

執行結果

doing
doing
./test.sh: line 8: other: command not found
  • 第二種,使用 (()) 括起來的判定表達式,這個表達式可以是比較表達式,也可以是一個數字,數字 0 表示假,其它數字表示真。這種用兩對括號括起來的表達式,其實就跟 c 語言很像了。
#!/bin/bash
if ((5>3 && 5>1)); then
    echo go
fi
if ((1)); then
    echo go
fi
if ((0)); then
    echo go
fi

執行結果

go
go

注意到 (()) 裏面的表達式直接用 >,< 等符號來作比較,這點要與測試區別開來。總的來說,就是這種 (()) 的寫法與高級語言更加相似。

  • 第三種,使用測試。測試的返回值爲 0 時表示真,非 0 時表示假,這個返回值 0 與 ((0)) 的意義是不一樣的。
if [[ 5 -gt 3 ]]; then
    echo go
fi

等價於

[[ 5 -gt 3 ]]
if (($?==0)); then
    echo go
fi
發佈了100 篇原創文章 · 獲贊 59 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章