$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
またはのcd
ようなプログラムも同じですcp
。テキスト/データストリームを処理するプログラムだけがパイプの入力を受け入れることができます。
答え2
プログラムがstdin
コマンドライン引数から入力を受け取るのか、コマンドライン引数として入力を受け取るのかは、デザイナーによって異なります。どちらの方法にも利点があります。しかし、ファイルを厳密に操作するプログラムの場合、ファイル名をコマンドライン引数として渡すのが一般的ですstdin
。
最も明白な理由は、ファイルからプログラムを実行する一般的なケースでは 。readlink file
代わりに:を入力する方が簡単ですecho file | readlink
。
より微妙な問題は正確さです。問題は、ファイル名を経由して渡されると、プログラムがあるstdin
ファイル名を別のファイル名と区別できる必要があることです。通常、これはファイル名がスペースまたは改行文字で区切られていると仮定して実行されますが、ファイル名にスペースを含めることができるため、これは正しくありません。より良いアプローチは、nullバイトを使用してファイル名を区切ることですが、nullバイトで区切られたファイルのリストを生成するのは不便です。
コマンドラインにファイル名を渡すと、シェルはプログラム内のすべての解析と参照を処理するため、この問題を回避できます。これを入力すると、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
次の代わりに使用することですwhich
。
$ type somecmd
somecmd is /home/saml/bin/somecmd
または単に値:
$ type -P somecmd
/home/saml/bin/somecmd
次に、次を実行しますreadlink
。
$ readlink $(type -P somecmd)
/bin/ls