xargs |入力をコマンドとして使用

xargs |入力をコマンドとして使用

以下の例が正しく機能すると思いました。

$ which -a python python3 pip | xargs -I {} {} --version
No '{}' such file or folder
$ which -a python python3 pip | xargs -I _ _ --version
No '_' such file or folder
$ which -a python python3 pip | xargs -I py py --version
No 'py' such file or folder

しかし、インタラクティブに実行するとまったく機能せず、文字列も置き換えません。最初の場所に関する特別なケースの説明は、マニュアルページには表示されません。なぜこれがうまくいかないのですか?

$ which -a python python3 pip | xargs -I py -p eval py --version
eval ~/.pyenv/shims/python --version?...y
xargs: eval: No such file or directory

これは正しく置き換えられるので、さらに驚くべきことです。

最初にこの主張をどのように使用できますか?... -I py sh -c "py --version"新しいサブプロセスが作成されるため、使用したくありません。現在の環境でコマンドを評価する方法を知りたいです。

答え1

存在するxargs -I replstr utility argumentsPOSIXの要件replstrでのみ交換でき、 では交換できargumentsませんutility。 GNUはxargsこれに関して互換性があります(busyboxは互換性がxargsありません)。

envこの問題を解決するには、次のユーティリティを使用できます。

which -a ... | xargs -I cmd xargs env cmd --version

xargs先行スペース、バックスラッシュ、一重引用符、二重引用符、改行、可能なバイトシーケンス、または入力が解釈される方法によって有効な文字を形成するためのブロック)。

またはより良い:

for cmd in (which -a ...)
  $cmd --version
end

これにより、ファイル名に問題がある文字は改行文字のみに制限されます。

とにかく、ここでは使用することも、eval使用したくありません。evalコマンドを実行する代わりにシェルコードを解釈するために使用されるシェル組み込みコマンド(POSIXシェルの特別な組み込みコマンド)。xargsはシェルの外部コマンドなので、次のようにシェルのインタプリタを起動しないと、シェルまたはシェルの組み込みコマンドを実行できません。

which -a ... |
  xargs -rd '\n' sh -c 'for cmd do "$cmd" --version; done' sh

私が知っている限り、インラインスクリプトはパラメータを受け入れることができないので、ここでsh代わりに使用してください。しかし、まだfishfishいいえevalこれらのファイル名がシェルコードとして解釈されることを望まないので、ここで使用することは意味がありません。

また、-rd '\n'GNU関連ではあるが存在しない問題を使用して、-Iすべての行の内容全体をユーティリティ(ここsh)に別々の引数として渡します。

関連情報