Shell腳本中的while和for循環(huán)

在日常工作中客情,學(xué)會使用shell編程溺森,可以在很大程度上替代手工重復(fù)性質(zhì)的工作巫橄,提高工作效率淘邻。從這點(diǎn)上來說,了解shell中循環(huán)的寫法非常關(guān)鍵湘换。下面介紹shell中的while循環(huán)和for循環(huán)宾舅。

1统阿、兩種循環(huán)基本寫法

常見的while和for循環(huán)的寫法,大概有如下幾種:
(1) 通過輸入重定向到while循環(huán)

while read line
do
echo $line
done < file(待讀取的文件)

(2) 通過cat命令輸出重定向到while循環(huán)

cat file(待讀取的文件) | while read line
do
echo $line
done

(3) for循環(huán)讀取命令輸出

for line in `cat file(待讀取的文件)`
do
echo $line
done

2筹我、兩種循環(huán)的區(qū)別

按照我的理解扶平,準(zhǔn)確的說,上面例子中while和for循環(huán)的區(qū)別在于:while循環(huán)會將每的內(nèi)容讀入到line變量蔬蕊;for循環(huán)中结澄,將讀入的內(nèi)容以IFS(shell中的環(huán)境變量,Internal Field Seperator岸夯,字段分隔符)為界分隔麻献,然后將各個分隔開的內(nèi)容,逐一讀入變量line猜扮。本質(zhì)上說勉吻,for循環(huán)讀取的是字段,只不過可以設(shè)置IFS為\n這樣能夠逐行讀取旅赢。
為了方便測試齿桃,我們用echo命令來實(shí)現(xiàn)多行文字的輸出。其中煮盼,echo命令的-e選項(xiàng)短纵,意思就是可以識別轉(zhuǎn)義字符能夠輸出行分隔符。如下例:

$ echo -e "a 12\nb 10"
a 12
b 10
$ 

(1) while逐行讀文件

$ echo -e "a 12\nb 10" | while read line
> do
> echo $line
> done
a 12
b 10
$ 

(2) for循環(huán)的默認(rèn)行為

$ for line in `echo -e "a 12\nb 10"`
> do
> echo $line
> done
a
12
b
10
$ 

(3) 通過改變IFS實(shí)現(xiàn)for循環(huán)按行讀入

$ IFS=$'\n'
$ for line in `echo -e "a 12\nb 10"`
> do
> echo $line
> done
a 12
b 10
$ 

除了上面常見循環(huán)的寫法孕似,while循環(huán)在逐行讀入的同時踩娘,還能夠根據(jù)IFS將整行的內(nèi)容分隔成多個字段,依次賦值給read后跟的變量名喉祭。如果變量數(shù)目多余字段的實(shí)際個數(shù)养渴,少的那些變量值為空;如果變量的數(shù)目少于字段實(shí)際個數(shù)泛烙,最后一個變量對所有后面的字段照單全收理卑。下面是一個例子:

$ echo -e "Tom 13\nLily 10 120cm\nJohn" | while read name age
> do
> echo "${name}: ${age}"
> done
Tom: 13
Lily: 10 120cm
John: 
$ 

3、一個簡單的shell循環(huán)應(yīng)用

假定有這樣一個場景蔽氨,需要在一個目錄中藐唠,查找好多關(guān)鍵詞。如果用shell搞定鹉究,我們就需要先將待搜索的關(guān)鍵詞寫入一個文件宇立,比如keyword.txt,每行一個關(guān)鍵詞自赔。然后妈嘹,寫一個腳本讀這個文件,取出每個關(guān)鍵詞绍妨,然后用grep命令查找润脸。下面是一個參考腳本的例子:

keyword_file='keyword.txt'
search_dir='/xx/path/'
result_file=result.txt

echo "Results:" | tee $result_file
cat $keyword_file | while read keyword
do
    echo "${keyword}:" | tee -a $result_file
    #word match, recursively search in directory and sub directory. only .java file will be searched. case insensitive. -l means only list file name
    grep -irw --include="*.java" "$keyword" "$search_dir" -l | tee -a $result_file
    echo "" | tee -a $result_file
done

運(yùn)行結(jié)果如下:

$ cat keyword.txt 
Polymerize
SortMeta
DataTube
$ sh search.sh 
Results:
Polymerize:
/xx/path/src/com/poly/merge/test/TestMergeSortDesc.java
/xx/path/src/com/poly/merge/test/TestMergeSortDescMultiSort.java
/xx/path/src/com/poly/merge/basic/Polymerize.java

SortMeta:
/xx/path/src/com/poly/merge/test/TestMergeSort.java
/xx/path/src/com/poly/merge/test/TestMergeSort16.java

DataTube:
/xx/path/UnitTest/com/poly/merge/basic/PolymerizeTest.java
/xx/path/src/com/poly/merge/test/TestMergeSort.java
/xx/path/src/com/poly/merge/test/DataTubeImp16.java
/xx/path/src/com/poly/merge/basic/Polymerize.java
/xx/path/src/com/poly/merge/basic/DataTube.java

$

注意:這里的keyword文件涉及到按行讀文件柬脸,所以這里要注意行分隔符必須是Unix/OS X風(fēng)格的LF, 也就是\n。如果文件的行分隔符是Windows風(fēng)格的CRLF毙驯,也就是\r\n倒堕,會什么都找不到。(我在windows電腦上爆价,將keyword文件分隔符設(shè)置為CRLF時垦巴,用git bash運(yùn)行搜索腳本,然后發(fā)現(xiàn)什么都搜不到铭段,最終發(fā)現(xiàn)是行分隔符的問題魂那。將行分隔符換成LF之后,搜索就一切正常了稠项。)

4涯雅、Shell腳本按行讀文件是行分隔符的坑

在用Shell編寫按行讀文件的腳本時,經(jīng)常會遇到行分隔符的坑展运,現(xiàn)象看起來十分詭異活逆。這里做下解釋。
說明:
在vim中可以通過命令:set ff=xxx來改變文本文件的行分隔符(fffileformat的縮寫)拗胜。其中xxx可以是dos(代表windows風(fēng)格的行分隔符蔗候,即CRLF,\r\n)埂软、unix(代表Unix和OS X風(fēng)格的行分隔符锈遥,即LF,\n)或者mac(代表Mac風(fēng)格的行分隔符勘畔,即CR所灸,\r)。
假設(shè)有一個文件有如下內(nèi)容炫七,行分隔符是windows格式的\r\n

$ cat text.txt 
in the house, there is a little horse.
finally, it won over a long race near the small inn.
all above is just a makeup story.
vaginally

寫如下的shell腳本test.sh爬立,按行讀該文件,然后輸出:

cat text.txt | while read line
do
    echo AAAA${line}BB;
done

輸出如下:

$ sh test.sh
BBAAin the house, there is a little horse.
BBAAfinally, it won over a long race near the small inn.
BBAAall above is just a makeup story.
BBAAvaginally

這個輸出十分詭異万哪,AAAABB并沒有按照預(yù)期的顯示在每行內(nèi)容的兩側(cè)侠驯,BB反而覆蓋掉了AAAA中的前兩個AA。原因就是因?yàn)檫@里按行讀的時候奕巍,分隔符是\n吟策,但是文本文件的行分隔符是\r\n。這樣的止,就導(dǎo)致每行讀出的內(nèi)容最后檩坚,有一個\r。而這個字符的意思是回車,也就是將光標(biāo)移動到行開頭效床。這樣,以第一行為例权谁,輸出BBBBin the house, there is a little horse.之后剩檀,輸出\r將光標(biāo)移動到行開頭,然后輸出AA就蓋掉了最前面的BB旺芽,出現(xiàn)了前面的效果沪猴。
\r字符也不是所有時候都是坑,比如我們想在命令行顯示一個跳動的時間采章,就要用到這個字符运嗜,讓后面的輸出蓋掉前面的。下面是一個例子time.sh

i=0
while [ $i -lt 30 ];
do     echo -ne "\r"`date` #you should remove new line too;
sleep 1;
i=$(($i + 1));
done

我在MacOS自帶的命令行上執(zhí)行上面的腳本悯舟,如果直接將腳本內(nèi)容復(fù)制到命令行執(zhí)行担租,這時候,會得到一個跳動的時間抵怎,不會輸出多行奋救。
如果通過命令sh time.sh來執(zhí)行,輸出效果是逐行輸出反惕。這里懷疑是sh指定的shell不是Bash尝艘,可能echo命令對于選項(xiàng)ne的支持有問題(這里可以看出echo的可移植性不好,在腳本編寫的時候姿染,盡量使用printf)背亥。,看了下悬赏,果然是:

$ which sh
/bin/sh

通過添加執(zhí)行權(quán)限和手動指定Bash執(zhí)行狡汉,都可以達(dá)到跳動的效果,如下:

$ chmod a+x time.sh 
$ ./time.sh 
2019年 8月14日 星期三 09時03分26秒 $ /bin/bash time.sh 
2019年 8月14日 星期三 09時03分35秒 $ 

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闽颇,一起剝皮案震驚了整個濱河市轴猎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌进萄,老刑警劉巖捻脖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異中鼠,居然都是意外死亡可婶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門援雇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矛渴,“玉大人,你說我怎么就攤上這事【呶拢” “怎么了蚕涤?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铣猩。 經(jīng)常有香客問我揖铜,道長,這世上最難降的妖魔是什么达皿? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任天吓,我火速辦了婚禮,結(jié)果婚禮上峦椰,老公的妹妹穿的比我還像新娘龄寞。我一直安慰自己,他們只是感情好汤功,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布物邑。 她就那樣靜靜地躺著,像睡著了一般滔金。 火紅的嫁衣襯著肌膚如雪拂封。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天鹦蠕,我揣著相機(jī)與錄音冒签,去河邊找鬼。 笑死钟病,一個胖子當(dāng)著我的面吹牛萧恕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肠阱,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼票唆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屹徘?” 一聲冷哼從身側(cè)響起走趋,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎噪伊,沒想到半個月后簿煌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鉴吹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年姨伟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豆励。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡夺荒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情技扼,我是刑警寧澤伍玖,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站剿吻,受9級特大地震影響窍箍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜和橙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望造垛。 院中可真熱鬧魔招,春花似錦、人聲如沸五辽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杆逗。三九已至乡翅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罪郊,已是汗流浹背蠕蚜。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悔橄,地道東北人靶累。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像癣疟,于是被迫代替她去往敵國和親挣柬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,378評論 0 5
  • 什么是運(yùn)維 術(shù)語名詞 IDC--(Internet Data Center)互聯(lián)網(wǎng)數(shù)據(jù)中心,主要服務(wù)包括整機(jī)租用扎狱、...
    lyh165閱讀 2,686評論 0 19
  • 一侧到、Python簡介和環(huán)境搭建以及pip的安裝 4課時實(shí)驗(yàn)課主要內(nèi)容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 5,734評論 0 10
  • 夢是名相,大夢非夢淤击,似霏霏細(xì)雨床牧,似緲緲云煙,似有還無遭贸。 “不要求什么心外的佛果戈咳,覺悟的心便是佛果,一切都是自性的幻...
    銥漩娜閱讀 1,107評論 1 4
  • 108+毛姆讀書隨筆+116-165/259+8/31 摘錄: 1踏堡,《呼嘯山莊》是一本奇特的書猎唁。它既是一本混亂的書...
    tracy2009m閱讀 163評論 0 0