$PATH
我有一個指向我想要編輯的文件中的腳本的符號連結。我忘記了文件路徑,所以我嘗試執行以下操作:
$ which my_script_link | readlink
我期望輸出檔案路徑,但它輸出
> readlink: missing operand
> Try 'readlink --help' for more information
我之前在其他情況下也見過類似的行為(例如嘗試將文件列表透過管道傳輸到 vim 中進行編輯)。我知道有解決方法,例如 subshell readlink $(which my_script_link)
,但我想了解為什麼在這種情況下,管道無法按照我認為應有的方式運作。
謝謝!
答案1
簡單地說,因為程式不是為了這樣做而寫的。由程式設計師決定他們的軟體是否可以從 STDIN 讀取或是否需要輸入檔案。在 的情況下readlink
,其man
頁面指出(強調我的):
readlink - 列印已解決符號連結或規範的檔案名稱
概要
閱讀連結[選項]...文件…
作為一般規則,從 STDIN 取得輸入的程式旨在以某種方式解析該輸入。當您透過管道傳輸資料時,readlink
它會收到一個文字流,但不知道如何處理它,因為它只處理文件而不處理其內容。對於像ls
orcd
或等程式也是如此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
或首選方式,使用type
instad of which
:
$ type somecmd
somecmd is /home/saml/bin/somecmd
或只是值:
$ type -P somecmd
/home/saml/bin/somecmd
現在我們運行readlink
:
$ readlink $(type -P somecmd)
/bin/ls