1. 程式人生 > >Bash腳本之循環

Bash腳本之循環

循環 遍歷

在編寫程序的時候有可能需要將一段代碼重復的執行0次、1次或多次,在這種時候僅僅只用順序執行結構就顯得有些捉襟見肘了,所以需要一個好的循環結構,而一個好的循環結構必須要包括兩個最重要的環節,第一個是進入循環的條件,當滿足這個條件的時候就開始循環;第二個是退出循環的條件,也就是當滿足這個條件的時候結束循環。來進行循環的命令大概有以下四個:

for:遍歷指定的列表;

while:根據邏輯判斷的結果;

until:根據邏輯判斷的結果;

select:死循環,利用循環機制提供選擇列表;

下面分別對這些命令進行介紹:


第一個介紹for命令,使用這個命令可以進行遍歷和循環,遍歷的意思是給出一個類似數組的東西,然後分別讀取數組中的每一個元素,格式為:

for VAR_NAME in LIST ; do 循環體; done

或寫成(與if相同,當do和for等命令在同一行的時候需要用分號“;”隔開,當不在同一行的時候就不需要了):

for VAR_NAME in LIST ; do
循環體
done

VAR_NAME為任意指定的變量名稱,依次從LIST中取值並賦值給VAR_NAME,循環體一般來說是能夠用到變量VAR_NAME的命令或命令的組合,循環的次數就為LIST中元素的個數,LIST的生成方式大致有以下六種:

1) 直接給出

比如:

創建一個腳本,然後將以下內容寫入:

#!/bin/bash
for i in a b c
do
echo "$i"
done


[[email protected] class]# bash forbl 
a
b
c

2) 純整數列表

使用命令seq:輸出一個整數列表

seq [FIRST [INCREMENT]] LAST
#!/bin/bash
for i in $(seq 4)
do
echo $i
done
[[email protected] class]# bash forseq 
1
2
3
4

3) 花括號展開

{FIRST..LAST}
#!/bin/bash
for i in {1..5}
do
echo $i
done
[[email protected] class]# bash forzhankai
1
2
3
4
5


4) 命令的執行結果的返回值

#!/bin/bash
for i in $(ls)
do
echo $i
done
[[email protected] class]# ls
forbl  forres  forseq  forzhankai
[[email protected] class]# bash forres 
forbl
forres
forseq
forzhankai


5) GLOBBING來對當前目錄下的文件進行名稱匹配

#!/bin/bash
for i in f*
do
echo $i
done
[[email protected] class]# ls
forbl  forglob  forres  forseq  forzhankai
[[email protected] class]# bash forglob 
forbl
forglob
forres
forseq
forzhankai

6) 某些變量的引用:$@, $*,這兩個符號在這裏基本沒有區別

#!/bin/bash
for i in $*
do
echo $i
done
[[email protected] class]# bash foryy a b c
a
b
c


註意:這個命令的這種使用方法是將LIST以空格和回車進行分開,也就是說如果一個元素中包含空格,那麽這個命令會將其當作兩個元素,例如:

#!/bin/bash
for i in a b c
do
echo "$i"
done
[[email protected] class]# bash forbl 
a
b
c
#!/bin/bash
for i in "a b" c
do
echo "$i"
done


[[email protected] class]# bash forbl 
a b
c


for進入循環的條件為LIST中有元素可以取用,那麽相對應的退出循環的條件為LIST中的所有元素都被取空,再無元素可用。 for循環有著自己獨特的特點,那就是幾乎不會出現死循環,但是在執行循環的過程中,這個命令會將LIST整個載入內存,如果LIST中的元素十分巨大,就會過多的消耗內存和CPU資源。


在使用for循環時可以配上一些技巧,例如嵌套使用,比如:

打印九九乘法表

#!/bin/bash
#
for I in {1..9} ; do
  for J in $(seq $I) ; do
    echo -ne "$I*$J=$[I*J]\t"
  done
  echo
done
[[email protected] class]# bash for99
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

除了使用for循環來進行遍歷,還可以使用控制變量來達到像C語言那樣的循環結構,格式為:

for (( 表達式1; 表達式2; 表達式3 )); do 命令; done

或寫成:

for (( 表達式1; 表達式2; 表達式3 )) ; do
循環體
done


在上面的格式中

表達式1為變量賦初始值;

表達式2為循環的退出條件;

表達式3為變量值的變化規律;


比如:

#!/bin/bash
for (( I=1; I<=100; I++ )); do
let SUM+=$I
done
echo $SUM
[[email protected] class]# bash forC
5050


在說完for命令之後,說一說while和until命令,while的格式如下:

while 命令; do 命令; done

或寫成:

while CONDITION ; do
循環體
done


進入循環條件:CONDITION為真;

退出循環條件:CONDITION為假;


until的使用格式如下:

until 命令; do 命令; done

或寫成:

until CONDITION ; do
循環體
done


進入循環條件:CONDITION為假;

退出循環條件:CONDITION為真;


這兩個命令十分相近,while是根據條件來執行循環體中的內容,而until是反過來,根據條件的取反來執行循環體中的內容,就是:

while CONDITION ; do CMD ; done

相當於

until ! CONDITION ; do CMD ; done


註意:對於while和until兩個循環結構來講,如果要實施變量增量操作,必須手動給出,也就是說如果使用一個變量實現自增則需要在循環體內加上一句命令來使變量自增,比如:

利用while和until循環結構,計算100以內所有整數的和;

#!/bin/bash
I=1
while [ $I -le 100 ] ; do
let SUM+=$I
let I++
done
echo $SUM
#!/bin/bash
I=1
until [ $I -gt 100 ] ; do
let SUM+=$I
let I++
done
echo $SUM


在循環體中,有的時候想讓循環終止,就需要continue和break這兩個命令,首先來看一下continue

continue [n]

提前結束第n層的本次循環,默認n為1,直接進入下一輪條件判斷,若符合循環進入條件,則開啟下一輪循環,例如:

#!/bin/bash
i=1
while [ $i -lt 3 ]
do
  echo "$i"
  let i++
  continue
  echo "b"
done
[[email protected] class]# bash whilecontinue
1
2

由上面這個例子可以看到在執行循環體中的內容的時候continue命令將“echo "b"”這條命令跳過了,繼續去執行下一個循環。這個例子是最基礎的使用方法,在日常的使用中我們可以加上一些判斷條件,比如說將這個continue命令放到if語句中,如果if一個條件成立,則不執行接下來的命令,舉例如下:

#!/bin/bash
i=0
while [ $i -lt 4 ]
do
  let i++
  if [ $i -eq 3 ] ; then
  continue
  fi
  echo "$i"
done
[[email protected] class]# bash whilecontinue1
1
2
4

由上面這個例子可見,在輸出“$i”的時候跳過了“3”這個數字。然後再來看一下break這個命令,這個命令和continue用法相同,但是它會直接跳出循環,也就是說使用這個命令之後循環就結束了,格式為:

break [n]

提前技術第n層循環,默認n為1,不再繼續後續循環,舉例如下:

#!/bin/bash
i=0
while [ $i -lt 4 ]
do
let i++
if [ $i -eq 2 ] ; then
break
fi
echo "$i"
done
[[email protected] class]# bash whilebreak
1
2

在這個腳本中我將上面的那個例子中的continue替換為break,然後將條件改為等於2,由執行後的結果可見原本應該輸出“1 2 3”的,現在僅僅輸出了“1”,這是因為當“$i”等於3的時候使用了break命令退出了此循環,所以接下來的命令都不會再執行了,甚至連使用continue時輸出的“2”也不再輸出。


當在寫腳本的時候可能需要使用無限循環,那麽可以使用如下的兩種寫法:

while true ; do
循環體
done

或者

until false ; do
循環體
done


這兩種寫法只是在原來的循環中改變了循環的條件,使條件一直滿足來達到無限循環的目的,在這裏就不進行舉例說明了。在此類的循環結構中,必須適當的使用continue和break,以保證循環不會一直持續下去,否則循環沒有終止條件,就會不停地執行,直到用戶使用強行停止的命令(強行停止一個命令的快捷鍵ctrl+c)。


使用while和until這兩個命令也能夠實現像for命令那樣的遍歷功能,使用方法如下:

while read LINES ; do
循環體
done < /PATH/FROM/SOMEFILE

或者

until ! read LINES ; do
循環體
done < /PATH/FROM/SOMEFILE

LINES為一個任意的變量名,可以在循環體中進行調用

/PATH/FROM/SOMEFILE為一個能夠被當前用戶讀取的文件,在這裏也可以使用輸入重定向來達到目的,比如:

#!/bin/bash
while read LINES
do
echo $LINES
done<<EOF
a
a b
a b c
EOF
[[email protected] class]# bash whileread
a
a b
a b c

這種遍歷的方法區別於for遍歷在於它可以忽略空格帶來的誤差,可以一行一行的進行讀取。


在說完了while和until之後,還有一個循環的命令select,這個命令創建的循環主要用於創建一個菜單式列表,供用戶進行選擇,列表是按照數字順序排列的,我們只要選擇數字即可。一般來講,select與case一起使用,select是一個無限循環結構,因此,必須在循環體中使用break命令以退出循環,或者可以使用exit命令直接終止腳本運行。select命令的使用格式如下:

select NAME [in 詞語 ... ;] do 命令; done

或者

select NAME [in LIST] ; do
命令
done

比如:

#!/bin/bash
select c in qwe asd zxc
do
:    #在這裏的“:”是代表繼續執行的意思,如果沒有這個命令會報錯
done
[[email protected] class]# bash select
1) qwe
2) asd
3) zxc
#?

在這個腳本執行之後會出現“#?”這個符號來提示你進行選擇,選擇的內容必須是上邊已經列出的那些選項。當選擇了一個之後,變量就會變成數字後對應的內容。比如在上面這個腳本中我使用了“c”來當作變量的名字,那麽在執行腳本之後,如果我輸入“2”並回車,c這個變量中保存的內容就變成了“asd”。


Bash腳本之循環