Shell進程替換(把一個命令的輸出傳遞給另一個命令)
進程替換和命令替換非常相似。命令替換是把一個命令的輸出結果賦值給另一個變量,例如dir_files=`ls -l`
或date_time=$(date)
;而進程替換則是把一個命令的輸出結果傳遞給另一個(組)命令。
為了說明進程替換的必要性,我們先來看一個使用管道的例子:
echo "http://www.beylze.com/d/file/20190908/y5jvity5mfg.html | read echo $REPLY
以上代碼輸出結果總是為空,因為 echo 命令在父 shell 中執行,而 read 命令在子 Shell 中執行,當 read 執行結束時,子 Shell 被銷毀,REPLY 變量也就消失了。管道中的命令總是在子 Shell 中執行的,任何給變量賦值的命令都會遭遇到這個問題。
使用 read 讀取數據時,如果沒有提供變量名,那么讀取到的數據將存放到環境變量 REPLY 中,這一點已在《Shell read》中講到。
幸運的是,Shell 提供了一種“特異功能”,叫做進程替換,它可以用來解決這種麻煩。
Shell 進程替換有兩種寫法,一種用來產生標準輸出,借助輸入重定向,它的輸出結果可以作為另一個命令的輸入:
<(commands)
另一種用來接受標準輸入,借助輸出重定向,它可以接收另一個命令的輸出結果:
>(commands)
commands 是一組命令列表,多個命令之間以分號;
分隔。注意,<
或>
與圓括號之間是沒有空格的。
例如,為了解決上面遇到的問題,我們可以像下面這樣使用進程替換:
read < <(echo "http://www.beylze.com/d/file/20190908/y5jvity5mfg.html) echo $REPLY
輸出結果:
http://c.biancheng.net/shell/
整體上來看,Shell 把echo "http://www.beylze.com/d/file/20190908/y5jvity5mfg.html
的輸出結果作為 read 的輸入。<()
用來捕獲 echo 命令的輸出結果,<
用來將該結果重定向到 read。
注意,兩個<
之間是有空格的,第一個<
表示輸入重定向,第二個<
和()
連在一起表示進程替換。
本例中的 read 命令和第二個 echo 命令都在當前 Shell 進程中運行,讀取的數據也會保存到當前進程的 REPLY 變量,大家都在一個進程中,所以使用 echo 能夠成功輸出。
而在前面的例子中我們使用了管道,echo 命令在父進程中運行,read 命令在子進程中運行,讀取的數據也保存在子進程的 REPLY 變量中,echo 命令和 REPLY 變量不在一個進程中,而子進程的環境變量對父進程是不可見的,所以讀取失敗。
再來看一個進程替換用作「接受標準輸入」的例子:
echo "C語言中文網" > >(read; echo "你好,$REPLY")
運行結果:
你好,C語言中文網
因為使用了重定向,read 命令從echo "C語言中文網"
的輸出結果中讀取數據。
Shell進程替換的本質
為了能夠在不同進程之間傳遞數據,實際上進程替換會跟系統中的文件關聯起來,這個文件的名字為/dev/fd/n
(n 是一個整數)。該文件會作為參數傳遞給()
中的命令,()
中的命令對該文件是讀取還是寫入取決于進程替換格式是<
還是>
:
如果是
>()
,那么該文件會給()
中的命令提供輸入;借助輸出重定向,要輸入的內容可以從其它命令而來。如果是
<()
,那么該文件會接收()
中命令的輸出結果;借助輸入重定向,可以將該文件的內容作為其它命令的輸入。
使用 echo 命令可以查看進程替換對應的文件名:
[c.biancheng.net]$ echo >(true) /dev/fd/63 [c.biancheng.net]$ echo <(true) /dev/fd/63 [c.biancheng.net]$ echo >(true) <(true) /dev/fd/63 /dev/fd/62
/dev/fd/
目錄下有很多序號文件,進程替換一般用的是 63 號文件,該文件是系統內部文件,我們一般查看不到。
我們通過下面的語句進行實例分析:
echo "shellscript" > >(read; echo "hello, $REPLY")
第一個>
表示輸出重定向,它把第一個 echo 命令的輸出結果重定向到/dev/fd/63
文件中。>()
中的第一個命令是 read,它需要從標準輸入中讀取數據,此時就用/dev/fd/63
作為輸入文件,把該文件的內容交給 read 命令,接著使用 echo 命令輸出 read 讀取到的內容。
可以看到,/dev/fd/63
文件起到了數據中轉或者數據橋梁的作用,借助重定向,它將>()
內部的命令和外部的命令聯系起來,使得數據能夠在這些命令之間流通。
beylze編程學院,一個分享編程知識和seo優化知識的網站。跟著beylze一起學習,每天都有進步。
通俗易懂,深入淺出,一篇文章只講一個知識點。
文章不深奧,不需要鉆研,在公交、在地鐵、在廁所都可以閱讀,隨時隨地漲姿勢。
文章不涉及代碼,不燒腦細胞,人人都可以學習。
當你決定關注beylze(公眾號:beylze),你已然超越了90%的其他從業者!