Mastering Shell Scripting: Comprehensive Guide
You are an expert shell scripting and command-line tutor. Your job is to help me master shell scripting, one-liners, and practical command-line techniques for my work.
In this thread, I will provide shell commands or topics that I would like to learn. For each one, please provide a comprehensive explanation that is thorough enough that I won’t need to consult any other resources. The explanation should cover:
- Core functionality and purpose
- All options and features (except extremely obscure ones), with clear descriptions
- Examples that cover every single option or feature you provided above, mixing basic to advanced, each with expected output or behavior
- Common use cases and best practices
- Potential pitfalls or gotchas to avoid
For all features and examples:
-
Mark any non-POSIX features with [Non-POSIX]
-
Specify the shell name for shell-specific features (e.g., [bash], [zsh], [ksh], [fish], etc.)
-
Tag implementation/platform differences if needed (e.g., [GNU], [BSD], [BusyBox], [macOS], [Linux], etc.)
Include at least 5 exercises of varying difficulty levels with solutions at the end.
Please provide complete, self-contained explanations in each response (don’t split them across multiple messages). For this first response only, please confirm that you understand these instructions without providing examples. From the second message onward, provide full explanations with examples and outputs. Please reply in Japanese.
承知しました。 今後は、各シェルコマンドやトピックについて、以下の内容を盛り込んだ包括的な解説を行います:
-
コアな機能と目的
-
主なオプションや機能(極端にマイナーなものを除き、全て網羅して明確に説明)
-
具体例(上記の全オプションや機能を網羅する形で、基本的な使い方から上級者向けテクニックまで示し、それぞれ期待される出力や動作も記載)
-
一般的な使用例とベストプラクティス(実務での活用方法や効率的な使い方の提案)
-
注意点や落とし穴(誤用しやすい点や陥りがちなミス、その回避策)
また、説明内ではPOSIX標準外の機能には [Non-POSIX] と明記し、シェル固有の機能(例:[bash], [zsh] など)は該当シェル名をタグとして付け加えます。GNU/BSD、BusyBoxやプラットフォーム([Linux], [macOS] 等)の実装差がある場合も適宜注釈し、明確に区別します。
最後に、各トピックに関して少なくとも5問の練習問題(難易度は初級から上級まで)を作成し、その解答と解説を回答の末尾に示します。これらの回答は全て一つのメッセージ内で完結するようにし、他の資料を参照しなくても十分理解できる内容を目指します。今後ともよろしくお願いいたします。
xargs
xargs コマンド徹底解説
xargsは、標準入力やファイルから読み込んだデータを引数に組み立ててコマンドを実行するためのUnix系コマンドです。大量のファイル名や文字列を一度にコマンドへ渡す場合や、パイプライン処理で前のコマンドの出力を後続コマンドの引数として利用したい場合に広く使われます。findコマンドと組み合わせてファイルを削除したり、grepと組み合わせて検索結果を処理したり、さまざまなシェルスクリプトで重宝するツールです。
本解説では、xargsのコア機能から主要なオプション・使い方まで網羅し、基本から応用までの例を示します。**POSIX標準外の機能には[Non-POSIX]**と明記し、特定環境に依存する機能には[GNU]や[BSD]などプラットフォームを示すタグを付けます。また最後に練習問題と解答を用意しましたので、理解度チェックにご活用ください。
コアな機能と目的
-
引数リストの構築と実行:
xargsは、入力として受け取った複数の項目(通常は改行区切りや空白区切りの文字列)をまとめて、指定したコマンドの引数列表に組み立て、一度に実行します。例えば、標準入力から取得したファイル名リストをまとめてrmコマンドに渡す、といった使い方ができます。これは、シェルのコマンド置換$( ... )で大量の引数を扱う場合に直面するコマンドライン長制限(ARG_MAX)を回避するためにも有用です。 -
デフォルトの動作:
xargsに特定のコマンドを指定しない場合、デフォルトでechoコマンドを実行します。つまり、入力をそのまま出力するだけになります。またxargsは引数をまとめる際に空白文字(スペースやタブ)や改行をデリミタ(区切り文字)として扱います。複数行の入力があれば、それぞれのトークンを空白で区切って一行にまとめ、echoで表示します(デフォルト動作の場合)。 -
引用符 (
"') やバックスラッシュ (\) の扱い: 標準入力中に引用符やバックスラッシュが含まれる場合、xargsはシェルのようにそれらを特別な文字とみなします。引用符で囲まれた部分は一つの引数として扱われ、バックスラッシュでエスケープされた文字はリテラルとして解釈されます。そのため、入力に"foo bar"という文字列があれば、引用符により空白を含む一つの引数「foo bar」として扱われます。xargsはこのように入力テキストをシェル的にトークナイズしますが、後述するオプションでこの挙動を変えることも可能です。 -
主な用途:
xargsの典型的な用途としては、findコマンドと組み合わせて多数のファイルに対して操作を行うケースが挙げられます。例えば、findで見つかったファイルを削除 (rm) したり、別のディレクトリへコピー (cp) したりする処理です。また、grepやcutの出力結果を他のコマンドに渡す、複数のURLに対してcurl/wgetを実行する、といった場面でも利用されます。特にパイプラインの後段で前段の出力をコマンドの引数にして実行したい場合に非常に便利です。シェルスクリプト内では、コマンドサブスティテューション(cmd $(other_cmd))よりもxargsの方が大量データ処理に適していることが多く、安全性(空白や特殊文字の扱い)や効率面で優れています。 -
実行タイミングと繰り返し:
xargsは入力からできるだけ多くの引数を集めてコマンドを実行し、残りの入力に対して再度コマンドを実行する、という動作を繰り返します。例えば1000行の入力があり、一度に100行ずつ引数にできる場合、10回に分けてコマンドを実行します(各回に100引数ずつ)。このように逐次的または複数回に分けてコマンドを起動することで、大量の引数も処理可能にしています。また必要に応じて、1回の実行あたりの引数数やコマンドライン長を制限したり、1引数ごとに個別に実行したりといった調整もオプションで行えます。 -
注意点: 処理対象のコマンド(後述の
utility)が標準入力を必要とするタイプのものである場合、xargsと組み合わせる際に注意が必要です。xargs自身が標準入力を消費してしまうため、後続のコマンドにはデフォルトでは入力が渡りません。例えば、xargsでvimやlessのような対話的プログラムを起動すると、標準入力が使えずにうまく動作しません。この場合、-oオプション [Non-POSIX](後述)を使って子プロセスの標準入力をターミナル(/dev/tty)にリダイレクトする必要があります。さらに、GNU版xargsでは空の入力に対するデフォルト動作が**「コマンドを一度は実行する」であり、BSD版xargsでは「何もしない」**という違いもあります(この違いは-rオプションで制御可能です)。
以上がxargsの基本的な役割と動作の概要です。次に、具体的なオプションと機能について詳しく説明します。
主なオプションと機能
xargsには多くのオプションがありますが、ここでは特に重要なものや実用性の高い機能を中心に解説します。各オプションのサポート状況として、POSIX規格外のものには[Non-POSIX]と付記し、GNU版特有の拡張には[GNU]、BSD系(macOS含む)特有の拡張には[BSD]と明記します。同じオプションでも実装によって挙動や有無が異なる場合がありますので、適宜言及します。
-
-0, --null【[GNU]、一部[BSD]実装、非POSIX】
標準入力からの項目区切りを空白や改行ではなくNUL文字(\0)に変更します。find -print0やgrep -lZのように、出力をNUL文字で区切るコマンドと組み合わせて使うためのオプションです。NUL文字はファイル名に含まれ得ない文字なので、スペースや改行など特殊文字を含むパス名でも安全に区切ることができます。このオプションを指定すると引用符やバックスラッシュも通常の文字として扱われる(特別な意味を持たない)ようになるため、入力は文字通りに解釈されます。
例:find . -type f -print0 | xargs -0 grep "TODO"は、現在ディレクトリ以下のすべてのファイルから文字列"TODO"を検索します(ファイル名にスペース等が含まれていても正しく処理)。 -
-d <delim>, --delimiter=<delim>【[GNU]、非POSIX】
項目の区切り文字を任意の単一文字<delim>に変更します。デフォルトでは空白と改行が区切りですが、このオプションを使うと指定した文字でだけ区切るようになります(引用符・バックスラッシュは-0同様特別扱いされなくなりリテラルとして処理)。<delim>には普通の文字だけでなく、\n(改行)や\t(タブ)などC言語風エスケープシーケンス、あるいは8進/16進コード(\013や\x0Aなど)を指定することも可能です。マルチバイト文字は指定できません。
例:printf "foo:bar:baz" | xargs -d ':' echoは、:区切りで入力を分割し、echoコマンドにfoo、bar、bazをそれぞれ引数として渡します。 -
-a <file>, --arg-file=<file>【[GNU]、非POSIX】
標準入力ではなく、指定したファイル(<file>)から入力を読み込むためのオプションです。xargs -a input.txt <command>とすると、input.txtの内容を標準入力の代わりに引数リストとして使用します。この場合、xargs自身は標準入力を消費しないので、パイプライン内でxargsを使う際に別の入力ソースを参照したい場合などに有用です。
例:xargs -a files.txt -n 1 rm -vは、files.txtに列挙されたファイルを一つずつ削除します(-vは削除したファイル名を表示するrmのオプション)。 -
-n <max-args>, --max-args=<max-args>
一度に実行するコマンドに渡す引数の最大数を<max-args>で指定します。デフォルトではシステムのARG_MAX制限に収まるだけ詰め込んで実行しますが、-nを使うと明示的に「この数までの引数で区切る」という制御ができます。例えば-n 1とすれば入力の各要素ごとにコマンドを起動します。-nで指定した数よりも少ない引数しか残っていなければ、その少ない分だけで実行します。
例:echo "1 2 3 4 5" | xargs -n 2 echoは、echoコマンドを一度につき2つの引数で複数回実行します(出力は「1 2」「3 4」「5」の3行)。 -
-L <number>, --max-lines=<number>
標準入力から読み込む行数単位でコマンドを実行します。<number>行ごとに区切ってコマンドを起動し、指定行数に満たない端数が残ればそれだけで1回実行します。例えば-L 3なら、入力を3行ずつまとめてコマンドに渡します。-L 1とすれば各行を個別に処理します(これは-nとの違いに注意:-nは「引数の数」上限、-Lは「行数」上限)。なお空行(改行だけの行)は非カウントとして次の行とまとめられます。-Lを使うと自動的にコマンドライン長制限を超えないよう-xオプション(後述)も有効になります。
例:seq 1 9 | xargs -L 3 echoは、seqで1~9を出力し、それを3行ずつまとめてechoに渡すので、結果として3つの行「1 2 3」「4 5 6」「7 8 9」が出力されます。 -
-x, --exit
引数リストを構築中に、もしコマンドライン長や引数数の上限を超えてしまう場合には、その場でxargsの処理自体を終了します(エラー終了)。通常xargsは上限に収まらない場合、適宜分割してコマンドを複数回に分けて実行しますが、-xを指定するとそうした分割を行わずに異常と見なします。これは、1回で処理しきれない量の引数があったら失敗させたいような場合に有用です。また、-Iや-Lを指定すると暗黙的に-xが有効になります。
例:seq 1 1000000 | xargs -n 1000000 -x echoは、もし100万個の数字すべてを一度のechoで表示できない環境(システムのARG_MAX制約超過など)ではエラー終了します。 -
-s <size>, --max-chars=<size>
コマンドライン全体の最大バイト数(文字数ではなくバイト数)を指定します。ここでのコマンドライン全体とは、コマンド名+引数+それぞれのNUL終端子+環境変数のサイズを全て含めた長さです。xargsはこのサイズを超えないように引数を詰め込み、超えそうになったらその手前でコマンドを実行します(次回以降に回す)。-sオプションがない場合、基本的にはシステムの制限(ARG_MAX)からマージン約2KBを引いた値が既定値として使われます。
例:printf "a%.0s" {1..1000} | xargs -s 100 echoは、長さ1000の文字列を生成し、コマンドラインが100バイト以下になるよう分割してechoします。結果として100バイトずつ区切られた文字列が複数行に分かれて出力されるでしょう。 -
-I <replstr>, --replace=<replstr>
挿入(置換)モードを有効にします。読み込んだ各入力行に対してコマンドを繰り返し実行し、コマンドライン中の<replstr>という文字列を入力行全体で置き換えて実行します。<replstr>は任意の文字列を指定できますが、典型的には{}や%などが使われます。例えば-I {}と指定すると、コマンド中の「{}」を入力の内容で置換してくれます。このモードでは改行のみを区切りとして入力を読み込み(空白文字は区切りとせずそのまま扱う)、デフォルトでは1行につき1回コマンドを実行します(-I指定時は暗黙的に-L 1が有効になります【[GNU]】)。-Iを使うと、自動的にコマンドライン長制限を厳密に守る-xも有効になります。
補足: GNU版では-Iの短縮形として**-i**オプション【[GNU]、非POSIX, 廃止推奨】も使用できます。-iの場合<replstr>省略時は{}がデフォルトになります(ただし-iは非推奨なので-Iの使用を推奨)。 -
-J <replstr>【[BSD]、非POSIX】
BSD系(macOS含む)のxargsで使える拡張機能で、最初に出現する<replstr>のみ入力内容で置換します。-Iとの違いは、-Jはコマンドラインの末尾ではなく途中に入力を挿入したい場合に適しています。つまり、置換文字列<replstr>をコマンドライン中に置いておくと、その位置に全入力(もしくは-nや-Lで区切られた分)が挿入されます。このとき他の引数の位置は変わらず、単に入力による引数列がその場に挿入される形です(-Iはコマンドの引数自体を入力1行に置換するため、1行につきコマンド全体を実行し直しますが、-Jは引数列の並びを固定して一部差し替えに使えるイメージです)。-Jを使う場合も<replstr>には%など区別しやすい文字が好まれます。
例:ls -1d [A-Z]* | xargs -J % -P 2 -n1 cp -Rp % /dest/dirは、カレントディレクトリ中の先頭大文字で始まるファイル/ディレクトリを2並列で/dest/dirにコピーします(コマンド中の%が入力由来のパスに置換されます)。この例ではcp -Rp <パス> /dest/dirという形式で実行され、-P 2により最大2プロセスが並行実行されます。 -
-R <replacements>【[BSD]、非POSIX】
こちらもBSD系xargsの拡張機能で、-Iと組み合わせて使用します。-Iで置換を行う際に、何個までの引数を置換対象とするかを指定できます。デフォルトでは5個までの引数内で<replstr>を置換しますが、-R 1のように指定すれば最初の1引数だけ置換し、2個目以降の引数はそのまま<replstr>が残ります(通常は使わないケースですが)。-R 0あるいは負の値を指定すると無制限(全引数で置換)となります。多くの場合デフォルト設定のままで問題ないため、特殊な要件がない限り使用する機会は稀です。 -
-S <replsize>【[BSD]、非POSIX】
こちらもBSD系xargsでの-I用拡張です。置換後の引数サイズの合計バイト数を指定します。デフォルトでは255バイトですが、-S 1024のように指定することで、置換結果の引数が長大になる場合にそのサイズ上限を拡張できます。-I使用時に入力行が非常に長く、複数の<replstr>置換によって引数リストが肥大化する場合に調整します。通常のファイル名やパス程度であれば255バイトで十分なので、これも特殊な状況でのみ指定するオプションです。 -
-p, --interactive
対話的モード(要ユーザ確認モード)を有効にします。xargsが実行しようとする各コマンド行を事前に表示し、実行して良いかユーザに確認を取ります。確認は端末からの入力を求め、yまたはYで始まる応答をした場合にそのコマンドを実行します(それ以外の応答ならスキップ)。この確認プロンプトは端末上でのみ機能し、標準入力が端末でない場合(パイプで繋がれている場合など)はコマンドは実行されません。GNU版では-pを指定すると自動的に-t(実行コマンドの表示)も有効になります。
例:echo "file1\nfile2" | xargs -p rm -vは、rm -v file1 file2を実行する前にrm -v file1 file2 ?...と確認を求め、yと答えれば実行、そうでなければキャンセルします。 -
-t, --verbose
実行内容の表示(トレース)を行います。xargsが実際に実行するコマンドラインを、実行前に標準エラー出力(stderr)へエコー表示します。これにより、xargsがどのようなコマンドを組み立てているか確認できます。デバッグやスクリプト開発時に便利なオプションです。
例:echo "data1 data2" | xargs -t -n1 echoとすると、実行のたびに例えば「echo data1」といったコマンド内容がstderrに表示され、その後stdoutにdata1が出力されます。 -
-o, --open-tty【[GNU]、[BSD]、非POSIX】
子プロセス(xargsが実行するコマンド)の標準入力を明示的に/dev/ttyに接続し直すオプションです。これにより、xargsがパイプから入力を読み込んでいる間も、起動されたコマンドはターミナルから入力を受け取れるようになります。対話型のプログラムやエディタなど、標準入力をユーザ操作に使うコマンドと組み合わせてxargsを使う場合に必要となります。
例:grep -l "TODO" *.txt | xargs -o -n1 viは、"TODO"を含むファイルを順にviエディタで開いていきます。このとき-oがないとviはパイプの終端(何もない入力)に接続されてしまい正常に起動できませんが、-oを付けることで各viは端末から入力を受け取れるようになります。 -
-r, --no-run-if-empty【[GNU]、非POSIX(BSD版ではデフォルト動作)】
入力が空の場合にコマンドを実行しないようにするオプションです。GNU版xargsでは入力が一つもなかった場合でもコマンドを1回は実行しようとします(例えばパイプ前段の出力が何もなかった場合でも、後続のコマンドがオプションなしでは実行されてしまう)。この-rを指定すると、標準入力が空っぽのとき一切コマンドを起動しません。BSD版xargsでは元々入力がなければ何もしない実装になっており、-rオプションは受け付けますが何の効果もありません(GNUとの互換性のため存在)。
例:printf "" | xargs echo Hello(標準入力が空)を実行した場合、GNU版ではHelloと出力されますが、xargs -r echo Helloとすれば何も出力されません。空の入力でコマンドを走らせたくない場合に-rを付けるのがベストプラクティスです。 -
-P <max-procs>, --max-procs=<max-procs>【[GNU]、一部[BSD]実装、非POSIX】
並列実行を行うためのオプションです。指定した数<max-procs>だけ、最大同時にコマンドを並行実行します。デフォルト1(つまり逐次実行)で、0を指定するとシステムが許す限り可能なだけ同時実行します。例えば-P 4とすれば、4プロセスまでのコマンドが同時に動きます。並列実行モードでは、入力から引数リストを読み取ってコマンドを起動する際、指定した数の子プロセスが動いている間は次の開始を待ち、いずれかが終了するとその次のコマンドを実行する、という動作を繰り返します。並列化によって全体の処理時間を短縮できますが、順序は保証されない(出力が混ざる可能性がある)ことに注意してください。
例:cat urls.txt | xargs -P 4 -n 1 curl -Oは、ファイルurls.txtに列挙されたURLに対し最大4つのcurl -Oダウンロードを並行で実行します。 -
--process-slot-var=<name>【[GNU]、非POSIX】
並列実行(-P)時に有用な高度なオプションです。各子プロセスの環境変数<name>に、そのプロセス固有の連番IDを設定して実行します。同時実行するプロセスごとに0,1,...といった番号が割り当てられ、子プロセス内で$<name>として参照可能です。この値は子プロセスが終了すると再利用されます。簡易的な負荷分散やログ取りなどで、どの並列スレッドが動いているか識別したい場合に利用できます。
例:seq 1 4 | xargs -P 2 -n1 --process-slot-var=JOB_ID bash -c 'echo "Job $JOB_ID processing {}"'を実行すると、2並列でbashが動き、JOB_IDに0または1が設定された状態でechoコマンドが走ります(どのジョブIDがどの入力を処理するかが表示されます)。 -
その他のロングオプション【[GNU]】: 上記で紹介した主要なオプションの他に、GNU版
xargsには--help(ヘルプメッセージ表示)や--version(バージョン情報表示)、--show-limits(システムのコマンドライン長制限の表示)といったオプションも存在します。--show-limitsを実行すると、現在のシステムでexec()に渡せる引数と環境の合計サイズや、xargsが内部で使用しているバッファサイズなどが表示されます。これらは日常的に使うものではありませんが、システム上の制約を調べたい場合に参考になります。
以上がxargsの主なオプションと機能です。POSIX標準に含まれるオプションはおおむね-p, -t, -I, -L, -n, -sあたりで、-0, -d, -Pなどは便利ですが環境に依存する拡張です。次章では、これらのオプションを実際に使用した例を示し、それぞれの動作を詳しく見てみましょう。
使用例(一例ごとの解説)
ここからは、xargsの具体的な使用例をいくつか取り上げ、それぞれのオプションや機能がどのように働くかを確認します。基本的なものから応用的なものまで順に紹介し、各例では実行コマンドとその結果(期待される出力や効果)を示します。
1. 基本的な使い方:入力をまとめてコマンド実行
最も基本となるxargsの使い方を示します。入力をそのまままとめてechoで表示する例です(xargsにコマンドを指定しなければechoが使われます)。
$ printf "Apple\nBanana\nCherry\n" | xargs
Apple Banana Cherry
上記では3行の文字列をパイプでxargsに渡しています。xargsは改行を区切りとして各単語をスペースで連結し、一度だけechoを実行しました。結果としてApple Banana Cherryと1行にまとめて表示されます。このように入力の各要素を並べて一つのコマンドに引数として渡すのが基本動作です。
もう一つ、入力が空白区切りの場合も試します。
$ echo "Red Green Blue" | xargs echo
Red Green Blue
この場合もxargsはスペースで区切られた3つの単語を引数としてまとめ、echoでそのまま出力しました。デフォルトの区切り文字は空白全般と改行であることが確認できます。
2. 引数の個数制限(-nオプション)
-nオプションを使うと、一度に渡す引数の数を制限できます。以下では6つの数値を入力し、-n 3で3つずつに区切ってechoを実行しています。
$ echo "1 2 3 4 5 6" | xargs -n 3 echo
1 2 3
4 5 6
xargsは最初の3つ(1 2 3)でechoを実行し、次に残りの3つ(4 5 6)でechoをもう一度実行しました。このように-nを使うと決まった数の引数単位でコマンドを複数回呼び出すことができます。-n 1とすれば各引数(ここでは数値)ごとに個別にechoを実行するため、6回echoが起動され6行出力されることになります。
3. 入力行数単位での実行(-Lオプション)
-Lオプションでは、入力の行数で区切って処理を行います。次の例では1~9の数字(9行)を-L 3で3行ずつまとめ、echoで出力しています。
$ seq 1 9 | xargs -L 3 echo
1 2 3
4 5 6
7 8 9
seq 1 9の出力は1行に1数字なので9行の入力です。-L 3により「3行ごと」にechoが呼ばれ、それぞれが1行にまとめられて出力されました。-L 1とすれば各行をそのまま処理するのでseq 1 9と同じ出力になります。また、-Lでは空白文字は区切りと見なされなくなるため、各行全体が一つの引数(トークン)として扱われます(これは-I使用時にも同様です)。
4. ファイルからの入力読み込み(-aオプション)【GNU拡張】
-aを使うと、パイプではなく直接ファイルから入力リストを読み込めます。例えば、以下のような内容のファイルitems.txtを用意したとします。
items.txt の内容:
alpha
beta
gamma
delta
このファイルの各行を入力としてコマンドを実行してみましょう。
$ xargs -a items.txt echo
alpha beta gamma delta
items.txtから読み込んだ4行が空白区切りで1行にまとめられ、echoに渡されました。-aを使用すると、items.txtの内容は改行区切りのデータ列として処理されます。通常の標準入力を使う場合と同じく、空白もデフォルトの区切り文字として解釈されます。例えば上記items.txtの各行にスペースが含まれている場合、単語単位に分割されてしまうので注意が必要です(その場合は次の例で紹介する-dや-0オプションが役立ちます)。
さらに、-aと-nを組み合わせることもできます。
$ xargs -a items.txt -n 2 echo
alpha beta
gamma delta
このように、ファイル入力でも-nによる引数数の制限が有効で、2つずつの単位でコマンドを実行しています。
5. 特殊文字や空白を含む入力の扱い(-d・-0による安全な区切り)
この例では、入力にスペースなどの特殊文字が含まれる場合のxargsの挙動と、それを正しく処理する方法を示します。まず、スペースを含む文字列を通常のxargsで処理した場合を見ます。
$ printf "file1\nfile name with spaces\n" | xargs -n1 echo
file1
file
name
with
spaces
2行の入力のうち、2行目 "file name with spaces" はスペースが含まれていたため5つのトークン(file, name, with, spaces)に分割されてしまいました。その結果、echoは5回実行され、それぞれの単語が別々の行に出力されています。これは望ましくない動作で、実際には「file name with spaces」という一つの名前として扱いたいところです。
この問題に対処するには、区切り文字を改行のみに限定するか、NUL文字区切りを使う必要があります。まず-d '\n'(デリミタを改行に限定)を試しましょう。
$ printf "file1\nfile name with spaces\n" | xargs -d '\n' -n1 echo
file1
file name with spaces
-d '\n'を指定したことで、各改行が唯一の区切りと見なされ、スペースは単なる一文字として処理されました。その結果、2行目もまるごと一つの引数としてechoに渡され、期待通り"file name with spaces"という単一の文字列が表示されています。
次に、-0オプションを使った例です。こちらは実際のコマンド利用シーンに即して、findとの組み合わせを見てみます。まずは**悪い例(問題が起こる例)**として、スペースを含むファイル名を通常のxargsで処理するケースです。
# 前提: ファイル "foo bar.txt" と "baz.txt" がカレントディレクトリに存在
$ find . -name "*.txt" -print | xargs ls -1
ls: ./foo: No such file or directory
ls: bar.txt: No such file or directory
./baz.txt
上記ではfindで*.txtファイルを検索し、その結果をxargs ls -1でリスト表示しようとしています。しかし、find出力の./foo bar.txtという名前がスペースで区切られてしまったため、lsコマンドには不正な引数./fooとbar.txtが渡され、エラーになっています。これは典型的な失敗例で、-printの代わりに-print0を使い、xargs -0で受け取るのが正解です。
$ find . -name "*.txt" -print0 | xargs -0 ls -1
./foo bar.txt
./baz.txt
-print0はNUL文字区切りで結果を出力し、xargs -0がそれを正しく1ファイル名ずつの引数として受け取ります。こうすることで、スペースや特殊文字(改行、タブなど)を含むファイル名でも問題なく処理できます。安全にファイルリストを扱うためのベストプラクティスとして、findとxargsを組み合わせる際はこの-print0 | xargs -0の形を用いることが推奨されます。
6. プレースホルダーによる引数差し替え(-Iオプション)
-Iオプションを使うと、入力の各行を特定のプレースホルダー文字列と置換してコマンドを実行できます。これにより、コマンドライン中の任意の位置に入力内容を挿入することが可能です。
以下は簡単な例として、プレースホルダー{}を使って挨拶文を生成するシナリオです。names.txtというファイルに名前リストがあるとします。
names.txt の内容:
Alice
Bob
Charlie
この各名前に対して「Hello, 名前さん!」という挨拶を表示してみます。
$ cat names.txt | xargs -I {} echo "Hello, {}さん!"
Hello, Aliceさん!
Hello, Bobさん!
Hello, Charlieさん!
xargsは入力から1行読み込むごとに(-I指定時は1行ずつになります)、echo "Hello, {}さん!"というコマンドの{}部分をその行の内容で置き換えて実行します。したがって、3行の入力から3回echoが実行され、それぞれに名前が差し込まれて出力されました。
プレースホルダーの複数回出現も可能です。例えば、入力の単語を2回繰り返して表示するには以下のようにします。
$ echo -e "one\ntwo\nthree" | xargs -I {} echo "{} -> {}"
one -> one
two -> two
three -> three
この例では、各行(one, two, three)について{} -> {}の両方が置換され、それぞれ1回のechoで二度繰り返した形になっています。
注意: GNU版xargsでは-I {}を指定するとデフォルトでそれぞれの入力行について個別のコマンド実行となります(暗黙の-L 1)。一方、BSD版xargsでも-I使用時は1行ごとに実行します。大量の入力行に対して-Iを使うと、それぞれ個別プロセスの起動となるためオーバーヘッドが大きくなる点には留意しましょう(多くの場合許容範囲ですが、何十万行もある場合は並列化や別の方法を検討)。並列化については後述の-Pと組み合わせることで、例えば-I {}と-P 4を併用し4並列で置換実行なども可能です。
7. コマンドの実行確認と表示(-pと-tオプション)
ファイル削除など破壊的な操作を行う際、xargs -pを使うと各コマンド実行前に確認を挟むことができます。また-tを使うとコマンド実行ログを表示できます。ここでは2つのオプションの動作を確認します。
例えば、誤って消したくないファイルを削除しようとしていないか一つずつ確認したい場合、以下のようにします。
$ printf "old1.tmp\nimportant.doc\nold2.tmp\n" | xargs -p -n1 rm
rm old1.tmp ?...y
rm: cannot remove 'old1.tmp': No such file or directory
rm important.doc ?...n
rm old2.tmp ?...y
rm: cannot remove 'old2.tmp': No such file or directory
ここではrmコマンドを1ファイルずつ実行するよう-n1を指定し、さらに-pで対話確認モードにしています。出力の例から、各ファイルに対してrm <filename> ?...とプロンプトが表示され、yと入力したものだけ実行されているのが分かります(old1.tmpとold2.tmpはyと答えたため削除実行していますが、この例では存在しなかったのでエラーが表示されています。important.docはnと答えたためスキップされました)。
-tオプションは確認は行わず常に実行コマンドをstderrに表示します。例えば-tのみで上記を実行すると:
$ printf "old1.tmp\nold2.tmp\n" | xargs -t -n1 rm -v
rm -v old1.tmp
rm: cannot remove 'old1.tmp': No such file or directory
rm -v old2.tmp
rm: cannot remove 'old2.tmp': No such file or directory
-tにより、実行されたコマンドライン(rm -v old1.tmpなど)が標準エラーにエコーされています。表示の末尾にある空白はxargsが区切りとして出力しているもので、実行されたコマンド自体には影響ありません(上記出力例では見やすさのため標準出力と標準エラーを混ぜて示しています)。-pと-tはデバッグや確認に非常に便利ですが、本番スクリプトでは不要であれば外しておくのがよいでしょう。
8. 並列実行による高速化(-Pオプション)
大量の独立した処理を行う場合、-Pオプションを用いることで所要時間を短縮できます。同時に複数の子プロセスを動かすため、CPUのコアを有効活用したり、I/O待ち時間を隠蔽したりできます。
例: URLの並列ダウンロード
複数のファイルをネットワークからダウンロードする場合、直列に実行すると時間がかかります。xargs -Pで並列化してみましょう。urls.txtにURL一覧があるとします。
urls.txt の内容:
http://example.com/file1.zip
http://example.com/file2.zip
http://example.com/file3.zip
http://example.com/file4.zip
これら4つのURLを、例えば2つずつ同時に取得するには次のようにします。
$ cat urls.txt | xargs -P 2 -n 1 curl -O
このコマンドはcurl -O <URL>を最大2プロセス並行で実行します。-n 1を指定しているため1つのURLにつき1回のcurlを起動し、同時に2つのcurlプロセスが走ることになります。ダウンロードの進捗表示などは各curlが行いますが、並行実行しているため表示が交錯することもあります(実行完了後、4つのファイルがすべてダウンロードされていることで成功が確認できます)。このように-Pオプションを使うと並列処理が可能ですが、順序に依存しない処理で使うことが重要です。順番が大切な処理(例えばファイルの分割結合など)には-Pを使わないようにしましょう。
例: 画像ファイルの一括変換を並列に実行
もう一つ、CPUを活かした例を示します。現在のディレクトリに大量の.pngファイルがあり、それらを.jpgに変換する処理を考えます。ImageMagickのconvertコマンドを使う場合、直列処理だと1ファイルずつ順番に変換しますが、xargs -Pで複数並行実行すれば高速化が期待できます。
$ ls *.png | xargs -P 4 -n 1 -I {} convert {} {}.jpg
上記ではls *.pngで取得したPNGファイル一覧を4並列で処理しています。-I {}でconvertコマンドの入力ファイル名と出力ファイル名の両方にプレースホルダーを入れ、一致する名前で.jpgを生成するようにしました。4つまでのconvertプロセスが同時に走るため、マルチコアCPU環境では処理時間がおよそ1/4になる可能性があります(I/Oボトルネックがなければ)。なお、この例では出力ファイル名に{}.jpgとしていますが、元の拡張子を置換して.jpgにするにはbasenameやパラメータ展開を組み合わせる必要があり、少し複雑になるため単純な形で示しています。
注意: 並列実行するコマンドの出力が標準出力・標準エラーにある場合、それらはターミナル上で混在して表示されます。ログを取る場合は各プロセスごとに別ファイルにリダイレクトするか、--process-slot-varを利用して識別子を付与すると良いでしょう。また、-Pで並列数を増やしすぎるとシステム負荷が高くなったり、かえって遅くなったりするので適切な数を指定することが大切です。
9. 対話的プログラムの起動(-oオプションの実用例)
前述の-o (--open-tty)オプションについて、実際の使いどころをもう少し詳しく説明します。-oはxargs経由で対話的なプログラム(ユーザ入力を必要とするプログラム)を起動する際に必要となることがあります。
例: 複数ファイルを順番にエディタで開く
検索でヒットした複数のファイルを、エディタで一つずつ開いて内容を確認・編集したい場合を考えます。例えば、.cファイルから"TODO"という文字列を探し、見つかったファイルをvimで開くには以下のようにします。
$ grep -l "TODO" *.c | xargs -o -n 1 vim
grep -lはマッチしたファイル名のみを表示するオプションで、この出力をxargsに渡しています。-n 1により1ファイルずつvimを起動し、-oを付けることで各vimの標準入力をターミナル(/dev/tty)に接続しています。こうすることで、vimは通常通り対話的に起動し、ユーザは編集を行えます。ファイルを閉じてvimを終了すると、xargsが次のファイルで再びvimを起動します。-oがない場合、vimはパイプからの入力にぶら下がる形となり、端末からの入力を受け取れず正しく動作しません(すぐに終了してしまう)。同様にlessやnanoなどでも-oが必要になるでしょう。
この例から分かるように、xargsで対話的コマンドを実行する際は-oオプションを付けるのがキーポイントです。ただしsudoのように一時的にターミナルを奪うコマンドや、プロンプトを内部で表示するコマンドの場合は別途注意が必要です(ケースバイケースですが、基本的に-oを付けてもうまくいかないものもあります。例えばxargsでsudoを複数回実行するとパスワード入力のタイミング管理が難しくなる等)。
以上、xargsの様々な機能と使用例を網羅的に紹介しました。次に、一般的な用途でのベストプラクティスと注意点についてまとめます。
一般的な使用例とベストプラクティス
-
findとの併用(安全なファイル操作):
xargsの最も一般的な用途は、findコマンドと組み合わせて多くのファイルに対して操作を行うことです。特に-print0とxargs -0の組み合わせは定石で、ファイル名中の空白や特殊文字で問題が起きないようにするベストプラクティスです。たとえば、古いログファイルを削除する場合:find /var/log -name "*.log" -mtime +30 -print0 | xargs -0 rm -fこれは
/var/log以下で30日以上前の.logファイルを見つけ、確実に削除する例です。-print0 | xargs -0にすることで、ファイル名にスペースや改行が含まれていても安全に削除できます。反対に、-print | xargsとしてしまうと予期せぬファイルを削除してしまうリスクがあります。 -
パイプライン処理の効率化: コマンドラインで大量のデータを扱う際、すべてのデータを一括で引数に渡せない場合があります。例えば数万件の入力を伴う操作では、単純なバッククォート(
command $(other_command))だと引数リストが長くなりすぎて失敗することがあります。xargsはデータ量に応じてコマンドを複数回実行してくれるため、こうした場合に非常に頼りになります。さらに-Pオプションで並列化すれば、大量データ処理の時間短縮も図れます。
ベストプラクティス: 何らかのコマンド出力を別のコマンドの引数に渡したいとき、以下のような順で検討すると良いでしょう:- コマンド自身のオプションで実現できないか(例:
grep -execやtar -Tなど)。 xargsを使う。特殊文字の扱いに注意しつつ、必要なら-0や-dを使う。- コマンド置換や
while readループで代替(ただし前述のデータ量・文字列安全性の問題に注意)。
特にfind ... -exec ... +の構文(プラスで終わる-exec)は内部的にxargsと同様の働きをするので、単純なケースではxargsを使わずに実現可能です。しかし、複数コマンドをパイプで繋ぐような柔軟な処理にはxargsが適しています。
- コマンド自身のオプションで実現できないか(例:
-
引数のエスケープ:
xargsを使う場合でも、シェルのエスケープ処理に気を配る必要があります。例えば、バッククォートやドル記号$などを含む文字列を扱う際、そのままではシェルが先に展開してしまう可能性があります。xargsに渡す前に適切にクオートする、あるいはprintfやecho -E(エスケープ無効)で安全に出力するなどの工夫が必要です。また、GNU版xargsでは-0や-d指定時には引用符やバックスラッシュは特別扱いされずリテラルになる点も思い出してください。つまり、前段のコマンドが出力でクォートした文字列は、xargs -0/-dではそのままクォート文字が残った状態で引数になることがあります(多くの場合問題ありませんが、シェルが解釈するわけではないことを認識しておきましょう)。 -
実行コマンドが標準入力を使う場合: コア機能のところでも触れましたが、
xargsで起動するコマンドが標準入力からの入力を必要とする場合は注意が必要です。xargsは自分が標準入力を読み込むため、子プロセスにはデフォルトでは入力が渡りません。対話型プログラム(エディタ、ページャなど)は-oオプションを使うことで解決できます。その他、例えばreadのように標準入力から値を読むシェル組み込みや、mysqlのように標準入力でクエリを受け取るコマンドをxargsで動かすと期待通りに動きません。この場合は、入力をパイプではなく別の手段で渡すか(例えば一時ファイルに書いて< fileで渡す等)、xargsを使わずシェルのループで処理する、といった代替策も検討しましょう。 -
一度に実行される引数数の把握:
xargsは内部でコマンドライン長を管理しつつ引数を詰め込んでいます。大量の引数を扱う場合、xargsが何回コマンドを起動するか把握しておくことも大切です。-nや-Lで明示していない場合、環境によっては1回で済む場合と複数回になる場合があります。GNU版では--show-limitsでヒントを得ることができますし、心配なら-tオプションで実際の実行コマンドを観察しても良いでしょう。特にコマンド起動のオーバーヘッド(プロセス起動にかかる時間)が無視できなくなる規模では、無闇に-n 1にせずある程度まとめて実行する方が効率的です。 -
エラー処理:
xargs自体やその子プロセスでエラーが起きた場合の挙動も知っておきましょう。xargsは子プロセス(実行したコマンド)の終了ステータスを確認し、255で終了した場合は「以降の処理を中止」します。これは子プロセス側で「致命的エラー」を255で示すケースを想定した挙動です。また、その他の子プロセスの非0終了ステータスや、xargs自体のエラー(コマンド実行失敗など)があれば、xargsは最後に1で終了します。一方で、途中の子プロセスが例えば2や3で失敗終了しても、255でない限りxargsは残りの入力を処理し続け、最終的な終了コードを1にするだけです(デフォルト動作の場合)。スクリプト内でxargsの成否を使って判断する場合、この仕様を念頭に置きましょう。ベストプラクティスとして、xargsで実行するコマンド側でエラーが起こり得るなら、終了コード255は使わないようにするか、捕捉して別の値に変えるなどしてxargsに中断されないようにすることもあり得ます。 -
xargsvs シェルループ:xargsでできることは、シェルのwhile readループなどでも実現可能です。しかし、xargsはC言語実装で効率よく動作し、プロセス起動回数も調整できるため、高速です。特に並列化やコマンドライン長管理はシェルスクリプトで手動で行うのは難しいため、これらが必要な場合はxargsの出番です。一方、順序制御や複雑な条件分岐を交えながら各入力を処理する場合は、シェルスクリプトでループを書く方が分かりやすいこともあります。状況に応じて併用しましょう。 -
その他のTips:
xargsを使っていて、「うまく引数が渡せない」「思ったよりコマンドが実行されない/されすぎる」といった場合、まず-tオプションで実行内容を確認するのがお勧めです。例えば引数中に予期せぬ改行やクォートが含まれていないか、-nや-Lの指定ミスでグルーピングがおかしくなっていないか、-Pで並列化しているせいで出力順序が混乱していないか、などを一つ一つ切り分けていきます。また、テストとして実際のコマンドの代わりにechoを使って出力だけ見る(デバッグ用にxargs ... echoとする)ことで、削除や変更を行う前に安全に挙動確認することも重要です。これらはシェルスクリプト全般のベストプラクティスですが、xargsでも特に気を配っておきたい点です。
よくある落とし穴・注意点
-
区切り文字の誤解:
xargsのデフォルトでは空白文字全般と改行が区切りになります。このため、単に改行で区切られた単語リストであっても各行の中にスペースやタブがあれば分割されてしまいます。意図せず引数がバラバラになる事故が多いポイントです。解決策: ファイル名や文章など空白を含む単位で扱う場合は、可能な限り-0(NUL区切り)を使う、もしくは-d '\n'で改行だけを区切りにする、あるいは入力側でクォートするなど対策を施しましょう。 -
引用符・バックスラッシュの扱い:
xargsはシェルほどリッチではありませんが簡易的なクォート解釈を行います。具体的には、"で囲まれた部分は一つの引数として扱われ、\でエスケープされた文字は次の文字をそのまま取り込みます。例えば入力行に"foo bar"とあればfooとbarはスペースを含む一語になりますし、\$HOMEと書かれていれば$HOMEというリテラル文字列になります(シェル展開されない)。この挙動を知らずにいると、思いがけず入力内のクォートが勝手に除去されてしまうことがあります。
対策: GNU版であれば-0や-dを指定するとクォートとバックスラッシュが特別扱いされなくなるため、必要に応じて使ってください。また、出力をxargsに渡す前にシェルスクリプト内でシングルクォートで囲むなどして、xargsに解釈させたくない文字はガードする方法もあります(ただしそのシングルクォート自体は入力の一部になるので、その後コマンドでどう扱われるか注意)。 -
空入力時の挙動: すでに述べたように、GNU版
xargsでは入力が空でもコマンドを1回実行しようとするという点に要注意です。特にrmやmvのように引数がないとエラーになるコマンドを想定していないままxargsを使うと、入力空の場合に想定外の動きをするかもしれません。
対策: GNU版を使う可能性があるスクリプトでは、習慣として-rオプションを付けることをお勧めします。BSD/macOS環境では冗長になりますが、付けておいて悪影響はありません(互換性のため無視されるだけ)ので、安全策として有効です。 -
並列実行時の出力順序:
-Pで並列化すると、標準出力・標準エラーの内容が混ざり合って時系列順に出力されません。特にログや結果の解析をする際には悩まされる点です。また、処理順序も同時に開始したもの同士では不定になります。
対策: 並列実行する場合は順序に依存しない処理に限る、どうしても順序が必要なら-P 1で直列に戻すか、別の方法で処理する、といった対処をします。出力を分離したい場合はプロセスごとに別ファイルにリダイレクトするか、後からソートできるように各出力にタグ(例えば先頭に入力番号を付与するとか)をつける工夫も考えられます。 -
コマンドライン長の限界:
xargsが自動でコマンドライン長を調整してくれるとはいえ、非常に長いパス名や環境変数があると、思ったより早く上限に達することがあります。引数をまとめすぎて一部が実行されないまま残ってしまう(通常は起こりませんが、-x指定時は発生し得る)ケースや、環境によってARG_MAXが小さくて何度もコマンドが分割実行されるケースなどです。
対策: 余裕を持った-nや-s指定をしておく、--show-limitsで事前に確認する、などで対応します。また、最新のLinux等ではARG_MAXが大きい(数百万バイト級)ので問題になりにくいですが、古いシステムや組み込み(BusyBoxなど)では要注意です。 -
非対応オプションの使用: スクリプトを他の環境へ持っていった際に、例えばMacで
xargs -dを使っていたために**"xargs: illegal option -- d"** といったエラーが出ることがあります。これはBSD版には-dがないためです。同様に-Pも古いMacではサポートされていません(macOS Big Sur以降ではBSD版でも-Pサポートあり)。LinuxでもBusyBox版xargsは機能が限定されています。
対策: 移植性を高めたい場合、POSIX規格内のオプションだけを使うのが安全です。具体的には-0や-dを避け、可能なら別の方法で空白安全性を確保する、-Pでの並列化も汎用性が必要ならGNU Coreutils(parallelコマンド)など他の手段を検討する、といったことがあります。とはいえ、現代ではGNU環境が多く-0は定番なので、シェルスクリプト中にxargsを使う際は環境要件を明記した上でGNU版前提でも構わないでしょう。システムによってxargsの挙動が異なる点だけ押さえておきましょう。 -
他のコマンドとの組み合わせ:
xargsを使うまでもなくコマンド自体が類似の機能を提供している場合があります。例えば、grep -Z(NUL区切り出力)と合わせてxargs -0を使うより、GNU版grepなら最初から-Zと-nullオプションを組み合わせてその後の処理までやってしまうコマンドもあります。また、最近のfindの-exec ... +構文や-deleteオプションなど、xargsを使わなくても実現できるケースもあります。xargsは非常に柔軟ですが、シンプルなケースは専用オプションで、複雑なケースはxargsでという使い分けも効率的です。
以上のベストプラクティスと注意点を踏まえれば、xargsコマンドを安全かつ効果的に活用できるでしょう。
それでは最後に、理解度を確認する練習問題を用意しました。基本的な使い方から応用テクニックまで、いくつかチャレンジしてみてください。
練習問題
次の問題に挑戦し、xargsの理解を深めましょう。各問には解答例も用意していますので、自分なりに考えた後で答え合わせをしてください。
-
列のグループ化: コマンドラインで
1 2 3 4 5 6 7 8 9と出力するにはseq 1 9を使います。この出力をxargsで受け取り、3つずつの数値を1行にまとめて表示してみてください(期待結果は3行に3つずつの数字が並ぶこと)。どのようなコマンドになりますか。 -
安全なファイル削除: 現在のディレクトリ内に拡張子
.tmpの一時ファイルが多数存在しています。findとxargsを使って、ファイル名にスペース等が含まれていても確実に削除できるコマンドを書いてください。また、入力が一件も無い場合に誤ってコマンドが実行されないように配慮してください。 -
プレースホルダーの活用:
files.txtというファイルに複数のファイルパスが書かれています。これらの各ファイルを/backupディレクトリにコピーしつつ、元ファイル名の後ろに拡張子.bakを付けた名前にしたいとします。例えばdata/report.txtというパスがあれば、コピー先は/backup/data/report.txt.bakとなるようにします。xargs -Iを使って、このコピー処理を行うコマンドを書いてください。cpコマンドの使用を想定してください(/backupディレクトリは既に存在し、cp -pでパーミッションも保存したコピーを行いたい)。 -
対話的な削除確認:
ls /tmp/*.logで一覧される/tmpディレクトリ内のログファイルを、1つずつ対話的に削除するスクリプトを作りたいとします。xargsを使ってユーザに確認しながらrmで削除するには、どのようなコマンドになりますか。 -
並列処理:
urls.txtに100個のURLが列挙されています。これらを高速にダウンロードするため、5プロセスずつ並列でwgetコマンドを実行したいです(出力ファイル名は元のファイル名に合わせる)。xargsを使って効率よくダウンロードを行うコマンドを書いてください。
解答と解説
-
列のグループ化:
seq 1 9 | xargs -L 3 echo
解説:seq 1 9で得られる1〜9の数列(9行の出力)をパイプでxargsに渡し、-L 3により3行ずつまとめてechoで出力しています。これにより、1 2 3,4 5 6,7 8 9という3列×3行の出力が得られます。-Lオプションは行数で区切る点がポイントです。 -
安全なファイル削除:
find . -name "*.tmp" -print0 | xargs -0 -r rm -f
解説:findでカレントディレクトリから拡張子.tmpを持つファイルを探し、-print0でNUL区切り出力します。xargs -0でそれを受け、rm -fコマンドに渡しています。-rオプションを付けることで、削除すべきファイルが一件も無い場合にはrmを実行しないようにしています(GNU版xargs特有の挙動への対処)。これにより、ファイル名に空白や特殊文字が含まれていても安全に、かつ無駄なコマンド実行も避けて削除できます。 -
プレースホルダーの活用:
xargs -a files.txt -I {} cp -p "{}" "/backup/{}.bak"
解説:xargs -a files.txtでファイル一覧を入力とし、-I {}でプレースホルダーを設定しています。cp -p "{}" "/backup/{}.bak"は各入力パス{}をそのままコピー元に、コピー先を/backup/以下に同じパス+拡張子.bakとして指定しています。{}は2カ所出てきますが、両方とも現在処理中のファイルパスに置換されます。例えばdata/report.txtが入力行であれば、コマンドはcp -p data/report.txt /backup/data/report.txt.bakとなり、意図したコピーが行われます。cp -pによりパーミッションやタイムスタンプを保存してコピーします。
補足:/backup直下に同じディレクトリ構造を作ってコピーするため、予め/backupフォルダと必要なサブディレクトリが存在している必要があります(存在しない場合はmkdir -pなどで事前に作成してください)。xargs自体でディレクトリ作成まで行うのは難しいため、必要ならコピーを2段階に分けて処理するなど工夫します。 -
対話的な削除確認:
ls /tmp/*.log 2>/dev/null | xargs -p -n 1 rm -v
解説:ls /tmp/*.logで/tmp内のログファイル一覧を取得し、パイプでxargsに渡しています(パターンにマッチしない場合のエラーメッセージを非表示にするため2>/dev/nullを付与)。-pオプションで削除ごとに確認を挟み、-n 1で1ファイルずつrm -vを実行しています。これにより、各ファイル削除時にrm <filename>?...とプロンプトが表示され、ユーザがyを入力すると例えば<filename> removed(rm -vのメッセージ)が出力されます。スキップしたい場合はnを入力すればそのファイルの削除は行われません。 -
並列処理:
xargs -a urls.txt -P 5 -n 1 wget -q
解説:urls.txt内の100個のURLを読み込み、wgetでダウンロードします。-P 5により最大5つのwgetを同時実行し、-n 1で各URLごとに個別のwgetプロセスを起動します。-qオプションはwgetの冗長な出力を抑制するために付けています(必要に応じて省略可)。各wgetはURLからファイル名を自動判別して保存するため、特別な指定がなくても元のファイル名で保存されます。並列ダウンロードにより、直列で100件ダウンロードするよりも高速に完了するでしょう。
補足: GNU版xargsを前提としています(-P使用のため)。BSD系でも-Pが使える環境であれば同様に動作します。
これらの問題を通じて、xargsコマンドの基本から応用まで一通り確認できたかと思います。xargsは慣れると非常に強力なツールです。様々な組み合わせを試しつつ、安全な使い方を心がけてマスターしてください。