假設我有乙個需求:從data.txt裡按行讀取乙個檔案,按格式"[行號]內容"輸出,再輸出讀取的行數。
data.txt:
youth is not a time.
it is a state of mind.
oh, you are right.
很簡單:
#!/bin/bash
i=0cat data.txt | while read line
do i=`expr $i + 1`
echo "[$i]$line"
done
echo $i
執行的結果卻令人大吃一驚:
-----輸出結果----------------------
[1]youth is not a time.
[2]it is a state of mind.
[3]oh, you are right.
0------------------------------------
為什麼是1?明明有3行的,應該是3啊!!!
原因就是:當while遇到管道(| ,即豎線符號)的時候,迴圈體會被fork到另乙個子shell去執行,此時while中i被改變,然而迴圈退出時,父shell的i並沒變,依舊是0,故而會輸出0。
什麼?你不信?那麼我們試試這個shell:
#!/bin/bash
while true
do sleep 20
cat data.txt | while read line
dosleep 1
done
done
言簡意賅,讓外層迴圈先跑起來,20s後,內迴圈開始跑,內迴圈就是使用管道。
$sh test.sh
20sne立刻檢視程序
$ps aux | grep sh
可以看到有如下程序:
----輸出結果--------------------------
kyle 22777 0.0 0.0 2216 540 pts/0 s+ 12:30 0:00 sh tread.sh
---------------------------------------
20s後,再次檢視:
$ps aux | grep sh
----輸出結果--------------------------
kyle 22777 0.0 0.0 2216 540 pts/0 s+ 12:30 0:00 sh tread.sh
kyle 22797 0.0 0.0 2216 540 pts/0 s+ 12:30 0:00 sh tread.sh
---------------------------------------
這下知道了為什麼i的值為0了吧。
-------------------------------------我是分割線---------------------------
如何避免以上情況?
答案:不要使用管道。
那用什麼?
答案:使用重定向。
#!/bin/bash
i=0while read line
do i=`expr $i + 1`
echo "[$i]$line"
done < data.txt
echo $i
再次執行:
-----輸出結果----------------------
[1]youth is not a time.
[2]it is a state of mind.
[3]oh, you are right.
3------------------------------------
最後,乙個for迴圈也可以達到效果,而且貌似這種速度更快:
for line in `cat data.txt`
do echo $line
done
搞定,收工!
while命令 shell指令碼
while test command do other commands donewhile 命令中定義的test command和if then語句的格式一模一樣。可以使用任何普通的bash shell命令,或者用test命令進行條件測試,比如測試變數值。while命令的關鍵在於所制定的test ...
Shell指令碼程式設計while迴圈
while 語句 do 執行語句 done接下來將會通過兩個簡單並且經常的使用的例子講解 bin bash i 1while i le 10 do i expr i 1 done echo i其中lele le表示不大於,exp rexpr expr 表示是相加運算 原始檔為 1 192.168.1...
shell 指令碼while迴圈和for迴圈
1.1 while 當條件為真時就進行迴圈,條件不成立時退出 提示使用者輸入 y 或 y 來終止程式。a用在判斷式中表示 and bin bash while aa y a aa y do read p please input y y to stop this program aa done1.2...