Q1xargsの役割として正しいものはどれですか?
xargs — 標準入力からコマンドを組み立てる
echo a b | xargs echoで標準入力を引数に並べ、-n1で1語ずつ実行し、-I{} で {} の位置に差し込み、find . -name '*.log' | xargsの一括処理を図解と端末で実習します。
標準入力を引数に変える — xargs と -n1
パイプは前のコマンドの出力を、次のコマンドの標準入力として渡します。ところがrmやechoは標準入力を読まず、引数に書かれた値だけを処理します。xargsは標準入力で受け取った内容を、後ろに書いたコマンドの引数に並べ替えて実行するコマンドで、echo a b | xargs echoならaとbが後ろのechoの引数になります。
xargsは既定では、受け取った語をできるだけまとめて 1 回の実行に渡します。-n1を付けると、1 語ごとに分けてコマンドを 1 回ずつ実行します。
| 書き方 | 意味 |
|---|---|
| xargs | 入力を引数に並べてコマンドを実行する |
xargs -n1 | 1 引数ずつコマンドを 1 回ずつ実行する |
xargs -I{} | {}を入力で置き換えて好きな位置に差し込む |
find ... | xargs | 見つけたものへまとめて処理を実行する |
| xargs echo rm | 実行されるコマンドを表示だけして確認する |
echoの出力は標準入力としてxargsへ渡り、引数に並べ替えられます。まとめて 1 回か、1 語ずつ 3 回かが-n1の分かれ目です。printf 'one two three\n' | xargs echo got: # got: one two three(まとめて 1 回)
printf 'one\ntwo\nthree\n' | xargs -n1 echo item: # item: one / item: two / item: three
置換文字列と find 連携 — -I{}
xargs -I{}は、入力の各行を`{}`の位置に差し込んでコマンドを組み立てます。{}はコマンドの途中など好きな位置に置けるので、echo file_{}.txtのように値の前後へ固定の文字列を付けた形を1 行ずつ実行できます。
findで見つけたファイルへ処理をかけたいときは、find ... | xargsの形が定番です。findが出力したパスをxargsが引数に並べ、検索結果へまとめて一括処理を実行します。-I{}と組み合わせれば、見つけた各パスを1 件ずつ`{}`へ差し込んで処理できます。
findが出したパスは 1 行 = 1 件としてxargsに渡り、-I{}が`{}`へ差し込んで 1 件ずつ実行します。printf 'alpha\nbeta\n' | xargs -I{} echo 'name = {}' # name = alpha / name = beta
mkdir -p logs # 素材ディレクトリを作成
touch logs/a.log logs/b.log # 2 ファイルを作成
find logs -name '*.log' | xargs -I{} echo 'found {}' # found logs/a.log / found logs/b.log
1 件ずつ確実に処理する — -n1 と -I{} の使い分け
-n1と-I{}はどちらもコマンドを 1 件ずつ実行しますが、値の入る位置と分割の単位が違います。-n1は語(空白や改行で区切られたかたまり)を 1 つずつ、コマンドの末尾の引数として渡します。-I{}は行を 1 つずつ、`{}`を書いた位置に差し込みます。
値を末尾に並べるだけなら`-n1`、{}.bakのように値の前後へ固定の文字列を付けたいなら`-I{}` を使います。
| 観点 | `-n1` | `-I{}` |
|---|---|---|
| 値の入る位置 | コマンドの末尾に並ぶ | {}を書いた位置に入る |
| 分割の単位 | 語(空白・改行区切り) | 行(1 行 = 1 件) |
| 向いている場面 | 引数を順に渡すだけの処理 | 値の前後に固定文字列を付けた形を組み立てる |
printf 'a\nb\n' | xargs -n1 echo prefix # prefix a / prefix b(末尾に並ぶ)
printf 'a\nb\n' | xargs -I{} echo {}_done # a_done / b_done(途中に差し込む)
一括処理の実践 — 確認してから実行する
実務では、findで集めた対象への一括コピーや一括削除にxargsを使います。-I{}は同じ値を2 か所以上に差し込めるので、cp 元 先のように引数を 2 つ取るコマンドにも使え、「元の名前 + .bak」のバックアップを一括で作れます。
rmのようなやり直しの利かない操作は、いきなり実行しません。xargs rmの前にxargs echo rmを流すと、実行されるはずのコマンドが表示されるだけで何も消えません。表示された対象を確認してからechoを外して本番を実行する、確認 → 実行の二段構えが安全な流れです。
rmの前にechoを挟んで対象を表示で確認してから実行します。mkdir -p cache
touch cache/a.tmp cache/b.tmp
find cache -name '*.tmp' | xargs echo rm # rm cache/a.tmp cache/b.tmp と表示するだけ
find cache -name '*.tmp' | xargs rm # 確認できたら本番を実行
理解度チェック
まずは1問ずつ答えてみましょう。
Q2printf 'a\nb\nc\n' | xargs -n1 echoはどう動きますか?
Q3xargs -I{}の{}は何を表しますか?