天天看點

管道指令 linux,linux shell 管道指令(pipe)使用及與shell重定向差別

看了前面一節:linux shell資料重定向(輸入重定向與輸出重定向)詳細分析 估計還有一些朋友是頭暈暈的,好複雜的重定向了。這次我們看下管道指令了。shell管道,可以說用法就簡單多了。

管道指令操作符是:”|”,它僅能處理經由前面一個指令傳出的正确輸出資訊,也就是 standard output 的資訊,對于 stdandard

error 資訊沒有直接處理能力。然後,傳遞給下一個指令,作為标準的輸入 standard input.

管道指令使用說明:

先看下下面圖:

管道指令 linux,linux shell 管道指令(pipe)使用及與shell重定向差別

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 通過出入檔案名讀取檔案内容