循環命令主要有三種:for(for又分兩種)、while、until,另外有兩個控制循環提前結束的命令:continue、break。
一、 for循環
for循環有兩種格式,一種bash shell基本格式,一種C語言風格的形式。
1. bash shell的基本格式
for variable [in words]
do
commands
done
for命令的強大之處在於可以通過多種方式來創建in後面的列表,例如:
- 直接由你列出所有要循環的值
#!/bin/bash
for i in f1 f2 f3 ;
do
echo $i is appoint ;
done
for str in 'This is a string'
do
echo $str
done
- 花括號創建 for i in {A..D}
#!/bin/bash
for i in {1..10}
do
echo $(expr $i \* 3 + 1);
done
- 路徑名展開 for in in dir*.txt
#!/bin/bash
for file in /proc/*;
do
echo $file is file path \! ;
done
- 命令替換 for i in $(seq 1 5) 或者 for i in `ls`
#!/bin/bash
for i in $(seq 1 10)
do
echo $(expr $i \* 3 + 1);
done
#!/bin/bash
for i in `ls`;
do
echo $i is file name\! ;
done
- 從文件中讀取(可更改IFS變量改變默認字段分隔符)
#!/bin/bash
file="states"
IFS=$'\n' #指定字段分隔符僅爲\n,默認爲空格、Tab與\n
for state in `cat $file`;
do
echo "visit beautiful $state"
done
2. C語言風格
# for (())中變量不以$開頭
for (( 初始值; 循環條件; 迭代量 ))
do
commands
done
例子
for (( i=0; i<5; i++ ))
do
echo $i
done
也允許在初始值中使用多個變量,分別進行處理,但循環條件只能有一個
for (( i=0, j=10; i<5; i++, j-- ))
do
echo "$i - $j"
done
二、 while循環
和if一樣,while也是利用命令的退出狀態判斷,只要退出狀態爲0,它就執行循環體內的內容
while commands
do
commands
done
例子
#!/bin/bash
count=1
while [ $count -lt 5 ]
do
echo $count
count=$((count + 1)) # 也可以寫成 count=$(expr $count + 1)
done
創建多個用戶
#!/bin/bash
input="users.csv"
while IFS=',' read -r userid name
do
echo "adding $userid"
useradd -c "$name" -m $userid
done < "$input"
來看一個複雜點的例子(here-document語法裏的內容必須頂格寫,否則會報錯)
#!/bin/bash
DELAY=3 # 結果展示時長
while [[ $REPLY != 0 ]]; do # 當輸入值不爲0,清除屏幕內容,顯示菜單並執行對應命令
clear
cat <<EOF
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
EOF
read -p "Enter selection [0-3] > "
if [[ $REPLY =~ ^[0-3]$ ]]; then # ~是對後面的正則表達式表示匹配的意思,匹配輸出1,不匹配輸出0
if [[ $REPLY == 1 ]]; then
echo "Hostname: $HOSTNAME"
uptime
sleep $DELAY
fi
if [[ $REPLY == 2 ]]; then
df -h
sleep $DELAY
fi
if [[ $REPLY == 3 ]]; then
if [[ $(id -u) -eq 0 ]]; then
echo "Home Space Utilization (All Users)"
du -sh /home/*
else
echo "Home Space Utilization ($USER)"
du -sh $HOME
fi
sleep $DELAY
fi
else
echo "Invalid entry."
sleep $DELAY
fi
done
echo "Program terminated."
菜單包含在 while 循環中,每次用戶選擇之後,能夠讓程序重複顯示菜單。只要 REPLY 不爲0,循環就會繼續,菜單就能顯示,用戶可以重新選擇。每次動作完成之後,會執行一個 sleep 命令,所以在清空屏幕和重新顯示菜單之前,程序將會停頓幾秒鐘,爲的是能夠看到選項輸出結果。 一旦 REPLY 等於0,則表示選擇了“退出”選項,循環就會終止,程序繼續執行 done 語句之後的代碼。
三、 until循環
也是利用命令的退出狀態判斷,但與while相反,退出狀態不爲0時才執行循環體內的內容
until commands
do
commands
done
簡單例子
#!/bin/bash
count=1
until [ $count -gt 5 ]
do
echo $count
count=$((count + 1))
done
四、 嵌套循環
上面幾種循環間都是可以相互嵌套的,可根據需要選擇,例如:
循環處理文件數據,結合前面提到的IFS環境變量,取出/etc/passwd各字段值
#! /bin/bash
IFS.OLD=$IFS
IFS=$'\n' #外層循環使用\n分段,解析出各行
for entry in $(cat /etc/passwd)
do
echo "Values in $entry -"
IFS=: #內層循環使用:分段,解析行中各字段
for value in $entry
do
echo " $value"
done
done
五、 控制循環
如果一旦啓動循環就只能等到完成所有迭代,有時是非常低效的,在符合某些條件後有時可以跳出循環。跳出方法有兩種:break和continue。
1. break
默認是立刻結束本層循環,執行外層內容(可能是外層循環或其他命令)。
改寫下前面的例子,如果用戶名爲oracle,跳出內層value循環,不再輸出本行值,開始下一次外層entry循環
#! /bin/bash
IFS=$'\n' #外層循環使用\n分段,解析出各行
for entry in $(cat passwd)
do
echo "Values in $entry -"
IFS=: #內層循環使用:分段,解析行中各字段
for value in $entry
do
if [ -z $value ] #由於:之間可能存在空字符串,需要額外加個判斷,否則執行==比較會報錯
then echo " $value"
elif [ $value == 'oracle' ]
then
break #跳出內層循環
else
echo " $value"
fi
done
done
可以看到oracle那一行沒有輸出具體字段值
其實break還可以指定要跳出哪層循環,默認爲1,即當前循環。指定方式爲
break n
稍微改寫一下前面的腳本,改爲跳出外層(即break 2)循環
#! /bin/bash
IFS=$'\n'
for entry in $(cat passwd)
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
if [ -z $value ]
then echo " $value"
elif [ $value == 'oracle' ]
then
break 2 #修改爲跳出外層循環
else
echo " $value"
fi
done
done
可以看到只執行到輸出Values in oracle那行,下面的字段輸出及外層的循環都沒有再執行了(若執行外層循環還會輸出grid用戶相關信息)
2. continue
默認結束本層本次循環,開始執行本層下一次循環。還是用剛纔的例子:
#! /bin/bash
IFS=$'\n'
for entry in $(cat passwd)
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
if [ -z $value ]
then echo " $value"
elif [ $value == 'oracle' ]
then
continue
else
echo " $value"
fi
done
done
可以看到沒有輸出oracle這個字段值,其餘都正常輸出了
其實continue也可以指定要繼續執行哪層循環,默認爲1,即當前循環。指定方式爲
continue n
稍微改寫一下前面的腳本,改爲繼續執行外層循環,即跳出本層循環(continue 2)
#! /bin/bash
IFS=$'\n'
for entry in $(cat passwd)
do
echo "Values in $entry -"
IFS=:
for value in $entry
do
if [ -z $value ]
then echo " $value"
elif [ $value == 'oracle' ]
then
continue 2
else
echo " $value"
fi
done
done
可以看到跟默認的break一個效果。
六、 循環結果處理
如果要將循環輸出的結果輸入文件,或者通過管道傳給其他命令,應該在done後面操作。
#!/bin/bash
count=1
while [ $count -lt 5 ]
do
echo $count
count=$((count + 1)) # 也可以寫成 count=$(expr $count + 1)
done > output.txt
#!/bin/bash
for file in /proc/*;
do
echo $file is file path \! ;
done | sort
參考