看了前面一節:linux shell資料重定向(輸入重定向與輸出重定向)詳細分析 估計還有一些朋友是頭暈暈的,好複雜的重定向了。這次我們看下管道指令了。shell管道,可以說用法就簡單多了。
管道指令操作符是:”|”,它僅能處理經由前面一個指令傳出的正确輸出資訊,也就是 standard output 的資訊,對于 stdandard
error 資訊沒有直接處理能力。然後,傳遞給下一個指令,作為标準的輸入 standard input.
管道指令使用說明:
先看下下面圖:

command1正确輸出,作為command2的輸入 然後comand2的輸出作為,comand3的輸入 ,comand3輸出就會直接顯示在螢幕上面了。
通過管道之後:comand1,comand2的正确輸出不顯示在螢幕上面
注意:
1、管道指令隻處理前一個指令正确輸出,不處理錯誤輸出
2、管道指令右邊指令,必須能夠接收标準輸入流指令才行。
執行個體:
[[email protected] shell]$ cat test.sh | grep -n 'echo'
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#讀出test.sh檔案内容,通過管道轉發給grep 作為輸入内容
[[email protected] shell]$ cat test.sh test1.sh | grep -n 'echo'
cat: test1.sh: 沒有那個檔案或目錄
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#cat test1.sh不存在,錯誤輸出列印到螢幕,正确輸出通過管道發送給grep
[[email protected] shell]$ cat test.sh test1.sh 2>/dev/null | grep -n 'echo'
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#将test1.sh 沒有找到錯誤輸出重定向輸出給/dev/null 檔案,正确輸出通過管道發送給grep
[[email protected] shell]$ cat test.sh | ls
catfile httprequest.txt secure test testfdread.sh testpipe.sh testsh.sh testwhile2.sh
envcron.txt python sh testcase.sh testfor2.sh testselect.sh test.txt text.txt
env.txt release sms testcronenv.sh testfor.sh test.sh testwhile1.sh
#讀取test.sh内容,通過管道發送給ls指令,由于ls 不支援标準輸入,是以資料被丢棄
這裡執行個體就是對上面2點注意的驗證。作用接收标準輸入的指令才可以用作管道右邊。否則傳遞過程中資料會抛棄。 常用來作為接收資料管道指令有:sed,awk,cut,head,top,less,more,wc,join,sort,split 等等,都是些文本處理指令。
管道指令與重定向差別
差別是:
1、左邊的指令應該有标準輸出 | 右邊的指令應該接受标準輸入
左邊的指令應該有标準輸出 > 右邊隻能是檔案
左邊的指令應該需要标準輸入 < 右邊隻能是檔案
2、管道觸發兩個子程序執行"|"兩邊的程式;而重定向是在一個程序内執行
這些都是網上總結很多的,其實隻要多加清楚用法,也一定有自己的一份不同描述。
執行個體:
#可以互相轉換情況
#輸入重定向
[[email protected] shell]$ cat test.sh| grep -n 'echo'
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#"|"管道兩邊都必須是shell指令
[[email protected] shell]$ grep -n 'echo'
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#"重定向"符号,右邊隻能是檔案(普通檔案,檔案描述符,檔案裝置)
[[email protected] shell]$ mail -s 'test' [email protected]
[c[email protected] shell]$ cat test.sh|mail -s 'test' [email protected]
#以上2個也相同,将test.sh内容發送到指定郵箱。
[[email protected] shell]$ (sed -n '1,$p'|grep -n 'echo')
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#這個腳本比較有意思了。由于前面是管道,後面需要把test.sh内容重定向到 sed ,然後sed輸出通過管道,輸入給grep.需要将前面用"()"運算符括起來。在單括号内的指令,可以把它們看作一個象一個指令樣。如果不加括号test.sh就是grep 的輸入了。
#上面一個等同于這個
[[email protected] shell]$ sed -n '1,$p'
5: echo "very good!";
7: echo "good!";
9: echo "pass!";
11: echo "no pass!";
#重定向運算符,在shell指令解析前,首先檢查的(一個指令,執行前一定檢查好它的輸入,輸出,也就是0,1,2 裝置是否準備好),是以優先級會最高
[[email protected] shell]$ sed -n '1,10p'
10:echo $total;
18:echo $total;
21: echo "ok";
#哈哈,這個grep又接受管道輸入,又有testsh.sh輸入,那是不是2個都接收呢。剛才說了"
#輸出重定向
[[email protected] shell]$ cat test.sh>test.txt
[ch[email protected] shell] cat test.sh|tee test.txt &>/dev/null
#通過管道實作将結果存入檔案,還需要借助指令tee,它會把管道過來标準輸入寫入檔案test.txt ,然後将标準輸入複制到标準輸出(stdout),是以重定向到/dev/null 不顯示輸出
#">"輸出重定向,往往在指令最右邊,接收左邊指令的,輸出結果,重定向到指定檔案。也可以用到指令中間。
[[email protected] shell]$ ls test.sh test1.sh testsh.sh 2>err.txt | grep 'test'
test.sh
testsh.sh
#目錄下面有:test,testsh檔案,test1.sh不存在,是以将ls 指令錯誤輸出輸入到err.txt 正确輸出,還會通過管道發送到grep指令。
[[email protected] shell]$ ls test.sh test1.sh testsh.sh &>err.txt | grep 'test'
#這次列印結果是空,&代表正确與錯誤輸出 都輸入給err.txt,通過管道繼續往下面傳遞資料為空,是以沒有什麼顯示的
#同樣">"輸出重定向符,優先級也是先解析,當一個指令有這個字元,它就會與左邊指令标準輸出綁定。準備好了這些,就等待指令執行輸出資料,它就開始接收
再概括下:
從上面例子可以看,重定向與管道在使用時候很多時候可以通用,其實,在shell裡面,經常是【條條大路通羅馬】的。一般如果是指令間傳遞參數,還是管道的好,如果處理輸出結果需要重定向到檔案,還是用重定向輸出比較好。
指令執行順序可以看下:Linux Shell 通配符、元字元、轉義符使用執行個體介紹
shell腳本接收管道輸入
有意思的問題:
既然作用管道接收指令,需要可以接收标準的輸入,那麼我們shell腳本是否可以開發出這樣的基本程式呢?(大家經常看到的,都是一些系統的指令作為管道接收方)
執行個體(testpipe.sh):
#!/bin/sh
if [ $# -gt 0 ];then
exec 0
#判斷是否傳入參數:檔案名,如果傳入,将該檔案綁定到标準輸入
fi
while read line
do
echo $line;
done
#通過标準輸入循環讀取内容
exec 0&-;
#解除标準輸入綁定
運作結果:
[[email protected] shell]$ cat testpipe.txt
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#testpipe.txt 隻是需要讀取的測試文本
[[email protected] shell]$ cat testpipe.txt | sh testpipe.sh
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#通過cat 讀取 testpipe.txt 發送給testpipe.sh 标準輸入
[[email protected] shell]$ sh testpipe.sh testpipe.txt
1,t,est pipe
2,t,est pipe
3,t,est pipe
4,t,est pipe
#testpipe.sh 通過出入檔案名讀取檔案内容