為什麼某些程式(如 readlink)不能從管道取得輸入?

為什麼某些程式(如 readlink)不能從管道取得輸入?

$PATH我有一個指向我想要編輯的文件中的腳本的符號連結。我忘記了文件路徑,所以我嘗試執行以下操作:

$ which my_script_link | readlink

我期望輸出檔案路徑,但它輸出

> readlink: missing operand
> Try 'readlink --help' for more information

我之前在其他情況下也見過類似的行為(例如嘗試將文件列表透過管道傳輸到 vim 中進行編輯)。我知道有解決方法,例如 subshel​​l readlink $(which my_script_link),但我想了解為什麼在這種情況下,管道無法按照我認為應有的方式運作。

謝謝!

答案1

簡單地說,因為程式不是為了這樣做而寫的。由程式設計師決定他們的軟體是否可以從 STDIN 讀取或是否需要輸入檔案。在 的情況下readlink,其man頁面指出(強調我的):

readlink - 列印已解決符號連結或規範的檔案名稱

概要
閱讀連結[選項]...文件

作為一般規則,從 STDIN 取得輸入的程式旨在以某種方式解析該輸入。當您透過管道傳輸資料時,readlink它會收到一個文字流,但不知道如何處理它,因為它只處理文件而不處理其內容。對於像lsorcd或等程式也是如此cp

答案2

程式是否從命令列參數取得輸入stdin或將其作為命令列參數由設計者決定。兩種方法都有其優點。然而,對於嚴格操作文件的程序來說,將文件名作為命令行參數傳遞通常比通過stdin.

最明顯的原因是,在常見情況下,即僅在文件上運行程序,更容易鍵入:readlink file而不是echo file | readlink.

一個更微妙的問題是正確性。問題是,當檔案名稱通過 傳遞時stdin,程式需要能夠區分一個檔案名稱和另一個檔案名稱。通常,這是透過假設檔案名稱由空格或換行符號分隔來完成的,但這是不正確的,因為檔案名稱可以包含空格。更好的方法是用空字節分隔文件名,但產生用空字節分隔的文件列表可能很不方便。

在命令列上傳遞檔案名稱可以避免此問題,因為 shell 會處理程式的所有解析和參考。您可以鍵入touch $'foo\nbar'touch正確地將其視為包含換行符的檔案名,而無需處理任何特殊的解析或參考本身。

話雖這麼說,如果您想stdin為特定程式傳遞文件,您可以。這就是xargs目的。xargs允許您採用僅在命令列上接受參數的程序,並使其通過stdin.

換句話說,它可以讓您執行以下操作:which my_script | xargs readlink

如果您想始終以readlink這種方式工作,您可以建立一個別名:alias readlink="xargs readlink"。這將允許您按照您最初想要的方式輸入which my_script | readlink

答案3

對於不透過 STDIN 取得參數的命令,您可以使用以下代碼雜註:

$ readlink $(which my_script_link)

例子

$ ln -s /bin/ls ~/bin/somecmd

現在檢查它是否在$PATH.

$ which somecmd
~/bin/somecmd

或首選方式,使用typeinstad of which

$ type somecmd
somecmd is /home/saml/bin/somecmd

或只是值:

$ type -P somecmd 
/home/saml/bin/somecmd

現在我們運行readlink

$ readlink $(type -P somecmd)
/bin/ls

相關內容