| 開発者 | さまざまなオープンソースおよび商用開発者 |
|---|---|
| オペレーティング·システム | Unix、Unix ライク、Plan 9、IBM i |
| プラットフォーム | クロスプラットフォーム |
| タイプ | 指示 |
xargs(「拡張引数」の略)[1]は、 UnixおよびほとんどのUnix系オペレーティングシステム上のコマンドであり、標準入力からコマンドを構築して実行するために使用されます。標準入力からの入力をコマンドの引数に変換します。
grepやなどの一部のコマンドは、awkコマンドライン引数または標準入力から入力を受け取ることができます。ただし、 や などの他のコマンドはcp引数echoとしてのみ入力を受け取ることができるため、xargs が必要になります。
GNU xargsの古いバージョンの移植版は、一般的な GNU Unix ライクなユーティリティのネイティブWin32移植版であるUnxUtilsコレクションの一部としてMicrosoft Windowsで利用可能です。 [2] wargsという完全に書き直されたコマンドは、オープンソースの TextTools [3]プロジェクトの一部です。xargsコマンドはIBM iオペレーティング システムにも移植されています。[4]
例
xargsコマンドの使用例の 1 つは、rmコマンドを使用してファイルのリストを削除することです。POSIXシステムには、コマンド ラインの最大合計長を表すARG_MAXがあるため、 [5] [6]、コマンドは「引数リストが長すぎます」というエラー メッセージ (exec システム コールのコマンド ラインの長さの制限を超えたことを意味します) で失敗する可能性があります。または(後者の呼び出しは、出力でグロブが拡張される可能性があるため、正しくありません。)
rm /path/*rm $(find /path -type f)
xargsこれは、引数のリストを許容できるほど小さいサブリストに分割するコマンド
を使用して書き直すことができます。
$ find /path -type f -print | xargs rm
上記の例では、findユーティリティはの入力にxargsファイル名の長いリストを供給します。xargs次に、このリストをサブリストに分割し、rmサブリストごとに を 1 回呼び出します。
xargsの一部の実装では、引数を使用して操作を並列化することもできます-P maxprocs。引数を使用して、入力引数リストでコマンドを実行するために使用する並列プロセスの数を指定します。ただし、出力ストリームは同期されない可能性があります。これは、--output file可能な場合は引数を使用し、処理後に結果を結合することで解決できます。次の例では、24 個のプロセスをキューに入れ、各プロセスが終了するのを待ってから別のプロセスを起動します。
$ find /path -name '*.foo' | xargs -P 24 -I '{}' /cpu/bound/process '{}' -o '{}' .out
xargs は、バッククォート表記 (または)で表される、多くのシェルのコマンド置換機能と同じ機能をカバーしていることがよくあります。xargsは、、、などの長いファイル リストを出力するコマンドにも適していますが、 を使用する場合に限ります(または同等の)。 を使用しないと、、およびスペースを含むファイル名をうまく処理できないためです。GNU Parallelは、ファイル名に、、およびスペースが含まれる可能性がある場合にfind、locateおよびgrepとの互換性が向上する同様のツールです(改行には が必要です)。
`...`$(...)findlocategrep-0--nullxargs-0'"'"-0
議論の配置
-Iオプション: 単一の引数
xargsコマンドには、コマンド ラインの末尾以外の位置にリストされた引数を挿入するオプションがあります。xargsの-Iオプションは、コマンドが実行される前に指定された入力に置き換えられる文字列を受け取ります。一般的な選択肢は です。
%
$ mkdir ~/backups
$ find /path -type f -name '*~' -print0 | xargs -0 -I % cp -a % ~/backups
置換する文字列は、コマンド部分に複数回出現する場合があります。at -Iall を使用すると、使用される行数が 1 回につき 1 行に制限されます。
シェルトリック: 任意の数
同様の効果を実現する別の方法は、起動コマンドとしてシェルを使用し、そのシェル内の複雑さに対処することです。次に例を示します。
$ mkdir ~/backups
$ find /path -type f -name '*~' -print0 | xargs -0 sh -c 'for filename; do cp -a "$filename" ~/backups; done' sh
sh行末の単語は、 POSIX シェルが sh -c位置パラメータ (argv) の「実行可能ファイル名」の部分を に埋め込むためのものです$0。この単語が存在しない場合は、最初に一致したファイルの名前が に割り当てられ$0、ファイルは にコピーされません。たとえば
~/backups、その空白を埋めるために他の単語を使用することもできます。my-xargs-script
は一度に複数のファイルを受け入れるためcp、次のように簡単に実行することもできます。
$ find /path -type f -name '*~' -print0 | xargs -0 sh -c 'if [ $# -gt 0 ]; then cp -a "$@" ~/backup; fi' sh
このスクリプトは、cp引数が渡された場合、指定されたすべてのファイルで実行されます。cpの呼び出しごとに の呼び出しが 1 回だけ実行されるため、より効率的ですsh。
セパレータの問題
多くの Unix ユーティリティは行指向です。これらのユーティリティは、行に、、またはスペースxargsが含まれていない限り、で動作します。一部の Unix ユーティリティは、レコード区切り文字としてNUL を使用できます (例: Perl (の代わりにand が必要)、( の使用が必要)、( の使用が必要)、(または が必要)、( の使用が必要))。 を使用するとこの問題に対処できますが、多くの Unix ユーティリティは区切り文字として NUL を使用できません (例: 、、、、、、、、) 。
'"-0\0\nlocate-0find-print0grep-z-Zsort-z-0xargsheadtaillsechosedtar -vwcwhich
しかし、多くの人はこれを忘れて、xargsも行指向であると想定しますが、これは事実ではありません(デフォルトでは、 は行内の改行とxargs空白で区切り、空白を含む部分文字列は一重引用符または二重引用符で囲む必要があります)。
セパレータの問題は次のように示されます。
#タッチの練習用にターゲットをいくつか作る important_file
touch 'not important_file'
mkdir -p '12" レコード'
find . -name not \* | tail -1 | xargs rm \! -name . -type d | tail -1 | xargs rmdir
を検索 上記を実行すると はimportant_file削除されますが、 というディレクトリ12" recordsも というファイルも削除されませんnot important_file。
適切な修正方法は GNU 固有の-print0オプションを使用することですが、tail(他のツールも) NUL で終了する文字列をサポートしていません。
# 上記と同じ準備コマンドを使用します
find . -name not \* -print0 | xargs -0 rm \! -name . -type d -print0 | xargs -0 rmdir
を検索 オプションを使用すると-print0、エントリは改行ではなくヌル文字で区切られます。これは、より詳細なコマンドと同じです。または、(delimiter) オプションを使用して(非 POSIX)行指向モードに切り替えると、より短くなります。find . -name not\* | tr \\n \\0 | xargs -0 rmxargs-dfind . -name not\* | xargs -d '\n' rm
ただし、ファイル名の改行は依然として問題となるため、
一般的には-0with を使用することをお勧めします。-print0
GNUは、同じオプションを持つように設計されたparallel代替品ですxargsが、行指向です。したがって、代わりにGNU Parallelを使用すると、上記は期待どおりに動作します。[7]
がオプションもオプションもxargsサポートしていないUnix環境(Solaris、AIXなど)では、POSIX標準では、すべての文字をバックスラッシュでエスケープするだけでよいと規定されています。[ 8]あるいは、GNU parallelを使用するか、の機能を使用することで、xargsをまったく使用しないようにすることもできます。
-0-dfind . -name not\* | sed 's/\(.\)/\\\1/g' | xargs rm-exec ... +find
一度に引数のサブセットを操作する
一度に 1 つまたは 2 つの引数しか受け付けないコマンドを扱う場合があります。たとえば、コマンドdiffは一度に 2 つのファイルに対して操作を行います。-nオプションは、xargs指定されたコマンドに一度に渡す引数の数を指定します。コマンドは、すべての入力がなくなるまで繰り返し呼び出されます。最後の呼び出しでは、入力が不十分な場合、必要な引数の数よりも少ない引数が渡される可能性があることに注意してください。を使用して、xargs入力を 1 行につき 2 つの引数に分割します。
$ echo { 0 ..9 } | xargs -n 2 0 1 2 3 4 5 6 7 8 9
一度に指定された数の引数に基づいて実行するだけでなく、オプションを使用して入力の各行に対してコマンドを呼び出すこともできます。一度に任意の数の行を使用できますが、1行を使用するのが最も一般的です。ここでは、すべてのgitコミットを親に対して実行する-L 1方法を示します。 [9]diff
$ git log --format = "%H %P" | xargs -L 1 git diff
エンコードの問題
の引数区切り文字の処理は、プログラムをデフォルト モードでxargs使用する場合の唯一の問題ではありません。ファイル名の操作によく使用されるほとんどの Unix ツール ( 、、など) はテキスト処理ツールです。ただし、Unix パス名は実際にはテキストではありません。パス名 /aaa/bbb/cccについて考えます。/aaa ディレクトリとその bbb サブディレクトリは、通常、異なる環境の異なるユーザーによって作成されます。つまり、これらのユーザーは異なるロケール設定を持つことができ、aaa と bbb は必ずしも同じ文字エンコーディングである必要はありません。たとえば、aaa は UTF-8 で、bbb は Shift JIS である可能性があります。その結果、Unix システム内の絶対パス名は、単一の文字エンコーディングではテキストとして正しく処理できない可能性があります。入力がテキストであることを前提とするツールは、このような文字列を処理すると失敗する可能性があります。
xargssedbasenamesort
この問題を回避する方法の 1 つは、このようなツールを C ロケールで実行することです。この方法では、基本的に入力バイトがそのまま処理されます。ただし、これにより、ツールの動作がユーザーが予期しない方法で変更される可能性があります (たとえば、大文字と小文字の変換動作に関するユーザーの期待の一部が満たされない可能性があります)。
参考文献
- ^ 「Unix 頭字語リスト: 完全なリスト」www.roesler-ac.de 。 2020 年 4 月 12 日閲覧。
- ^ 「いくつかの GNU ユーティリティのネイティブ Win32 ポート」unxutils.sourceforge.net。
- ^ 「Windows 用のテキスト処理ツール」。
- ^ IBM . 「IBM System i バージョン 7.2 プログラミング Qshell」(PDF) . 2020 年 9 月 5 日閲覧。
- ^ 「GNU Core Utilities よくある質問」 。2015年12 月 7 日閲覧。
- ^ 「新しいプロセスの引数の最大長」www.in-ulm.de。
- ^ xargs と GNU Parallel の違い。GNU.org。2012 年 2 月にアクセス。
- ^ – シェルおよびユーティリティ リファレンス、The Single UNIX 仕様、バージョン 4、The Open Group
- ^ Cosmin Stejerean. 「xargs について (おそらく) 知らなかったこと」 。2015年12 月 7 日閲覧。
外部リンク
- : 引数リストを構築し、ユーティリティを呼び出す – シェルおよびユーティリティ リファレンス、The Single UNIX 仕様、バージョン 4、The Open Group
