循環中的重定向
或許你應該在其他腳本中見過下面的這種寫法:
while read line
do
…
done < file
剛開始看到這種結構時,很難理解< file是如何與循環配合在一起工作的。因為循環內有很多條命令,而我們之前接觸的重定向都是為一條命令工作的。這里有一個原則,這個原則掌握好了,這個問題就很簡單了:
對循環重定向的輸入可適用於循環中的所有需要從標准輸入讀取數據的命令;
對循環重定向的輸出可適用於循環中的所有需要向標准輸出寫入數據的命令;
當在循環內部顯式地使用輸入或輸出重定向,內部重定向覆蓋外部重定向。
上面的while結構中,read命令是需要從標准輸入中讀取數據的。我們來詳細了解一下read命令的用法吧,這個命令是shell腳本中使用頻率最高的命令之一。
read
先來看一下read的命令語法:
read arg1 arg2 arg3 arg4 …
read是一個用來賦值的命令,它需要從標准輸入獲得值,然后把這些值按位置依次賦值給變量arg1、arg2、arg3、arg4…,輸入的時候以空格作為字段分隔符。
read的一個最大特性是可以在腳本中產生交互,因為它從標准輸入讀取數據。read之所以很常用,一是因為我們經常需要賦值,二是因為它可以交互,三是read能夠一次給多個變量賦值。
$ read host ip name
linux 10.0.0.1 licong
$ echo $host $ip $name
linux 10.0.0.1 licong
$
可以看到,linux、10.0.0.1、licong分別被賦值給了變量host、ip和name。再看:
$ read host ip
linux 10.0.0.1 licong
$ echo $host
linux
$ echo $ip
10.0.0.1 licong
$
當我們輸入的字段比變量數目多時,最后一個變量的值將不只一個字段,而是所有剩余的內容;當輸入字段比變量數少時,多余的變量將是空值,你可以自己試試。現在我們再來看
while read line
do
…
done < file
read通過輸入重定向,把file的第一行所有的內容賦值給變量line,循環體內的命令一般包含對變量line的處理;然后循環處理file的第二行、第三行。。。一直到file的最后一行。還記得while根據其后的命令退出狀態來判斷是否執行循環體嗎?是的,read命令也有退出狀態,當它從文件file中讀到內容時,退出狀態為0,循環繼續驚醒;當read從文件中讀完最后一行后,下次便沒有內容可讀了,此時read的退出狀態為非0,所以循環才會退出。
另一種也很常見的用法:
command | while read line
do
…
done
如果你還記得管道的用法,這個結構應該不難理解吧。command命令的輸出作為read循環的輸入,這種結構長用於處理超過一行的輸出,當然awk也很擅長做這種事。
APP_FILE=./aabb(這個是多行文件)
cat $APP_FILE|while read line
do
ssh -q $line ls /home/admin
done
fail: 只執行了一次,就退出了循環
cat $APP_FILE|while read line
do
ssh -q $line ls /home/admin
done
fail: 只執行了一次,就退出了循環
這里的問題是所有的內容都一起讀取出來寫到緩存里面了,讓SSH重定向出去了
注意:
1. ssh命令在每次執行時,會讀取所有的標准輸入中的內容。
cat file |ssh 1.1.1.1 cat 會讀取所有文件的內容
2. 對於while循環,當按照如下方式使用時:
cat file | while read line
這里使用重定向,將文件內容輸入到while命令,while命令每次使用read從輸入中讀取一行數據。
問題就在這里,如果在while循環中調用了ssh命令,那么ssh就會把當前輸入中所有的數據讀走,也就是cat file重定向給while命令的數據,都被ssh命令讀走了,以至於下次循環的時候,read讀到的內容為空,導致循環提前結束。
解決這個問題兩種方式
1. ssh -n 使用-n參數
2. ssh xxxx < /dev/null重定向shell命令的輸入
主要參數說明:
-l 指定登入用戶
-p 設置端口號
-f 后台運行,並推薦加上 -n 參數
-n 將標准輸入重定向到 /dev/null,防止讀取標准輸入
-N 不執行遠程命令,只做端口轉發
-q 安靜模式,忽略一切對話和錯誤提示
參考文章
http://blog.163.com/clevertanglei900@126/blog/static/11135225920118742327322/