順番に読み進めながら学べます

xargs — 標準入力からコマンドを組み立てる

echo a b | xargs echoで標準入力を引数に並べ、-n1で1語ずつ実行し、-I{} で {} の位置に差し込み、find . -name '*.log' | xargsの一括処理を図解と端末で実習します。

標準入力を引数に変える — xargs と -n1

パイプは前のコマンドの出力を、次のコマンドの標準入力として渡します。ところがrmechoは標準入力を読まず、引数に書かれた値だけを処理します。xargs標準入力で受け取った内容を、後ろに書いたコマンドの引数に並べ替えて実行するコマンドで、echo a b | xargs echoならabが後ろのechoの引数になります。

xargsは既定では、受け取った語をできるだけまとめて 1 回の実行に渡します。-n1を付けると、1 語ごとに分けてコマンドを 1 回ずつ実行します。

書き方意味
| xargs入力を引数に並べてコマンドを実行する
xargs -n11 引数ずつコマンドを 1 回ずつ実行する
xargs -I{}{}を入力で置き換えて好きな位置に差し込む
find ... | xargs見つけたものへまとめて処理を実行する
| xargs echo rm実行されるコマンドを表示だけして確認する
xargs が入力を引数に並べ替える
echo a b c標準入力a b c| xargs echo| xargs -n1 echoecho a b cまとめて 1 回echo a / b / c1 語ずつ 3 回出力パイプで渡すパイプで渡す1 回だけ実行1 語ごとに実行
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

printf 'red\ngreen\nblue\n' > colors.txtで 3 行の素材ファイルを作成してください。

cat colors.txtの出力をパイプでxargsに渡し、echoの引数に並べてまとめて 1 回表示してください。

③ 同じ入力をxargsに渡し、1 語ずつ分けて実行するオプションを付けて、echoが 1 行ずつ 3 回動くことを確認してください。(正しく実行できれば解説が表示されます)

Linux console
0 / 3 実行済み
Loading Linux Terminal...

置換文字列と find 連携 — -I{}

xargs -I{}は、入力の各行を`{}`の位置に差し込んでコマンドを組み立てます。{}コマンドの途中など好きな位置に置けるので、echo file_{}.txtのように値の前後へ固定の文字列を付けた形を1 行ずつ実行できます。

findで見つけたファイルへ処理をかけたいときは、find ... | xargsの形が定番です。findが出力したパスをxargsが引数に並べ、検索結果へまとめて一括処理を実行します。-I{}と組み合わせれば、見つけた各パスを1 件ずつ`{}`へ差し込んで処理できます。

find が見つけたものを xargs で処理する
find . -name '*.log'a.logb.log| xargs -I{} echo {}{} に各行を差し込むecho a.logecho b.logパスを出力パイプで渡す1 行目を実行2 行目を実行
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

printf 'cat\ndog\n' | xargsに置換文字列のオプションを付け、各入力をpet = {}{}の位置に差し込んで表示してください。

mkdir -p dataでディレクトリを作り、touch data/x.txt data/y.txtで 2 つのファイルを作成してください。

find data -name '*.txt'の出力をパイプでxargsに渡し、置換文字列で各パスをecho 'hit {}'{}に差し込んで表示してください。

④ 素のfind data -name '*.txt' | xargs echoも実行し、-I{}無しでパスが末尾に並ぶ形と見比べてください。

Linux console
0 / 5 実行済み
Loading Linux Terminal...

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(途中に差し込む)

printf 'log1\nlog2\n' | xargsに 1 語ずつ実行するオプションを付け、echo fileの引数として 1 つずつ渡してください。

② 同じ入力をxargsに渡し、置換文字列のオプションでecho {}.bak{}に差し込んでください。

③ 末尾に並ぶ場合と途中に差し込む場合で出力がどう変わるか見比べてください。

Linux console
0 / 2 実行済み
Loading Linux Terminal...

一括処理の実践 — 確認してから実行する

実務では、findで集めた対象への一括コピーや一括削除xargsを使います。-I{}は同じ値を2 か所以上に差し込めるので、cp 元 先のように引数を 2 つ取るコマンドにも使え、「元の名前 + .bak」のバックアップを一括で作れます。

rmのようなやり直しの利かない操作は、いきなり実行しません。xargs rmの前にxargs echo rmを流すと、実行されるはずのコマンドが表示されるだけで何も消えません。表示された対象を確認してからechoを外して本番を実行する、確認 → 実行の二段構えが安全な流れです。

一括削除は表示で確認してから実行する
find . -name '*.tmp'a.tmpb.tmp| xargs echo rm| xargs rmrm a.tmp b.tmpと表示するだけ2 ファイルをまとめて削除対象を出力① まず確認② 確認できたら何も消えない本番を実行
やり直しの利かない操作は、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        # 確認できたら本番を実行

mkdir -p workで作業用ディレクトリを作り、touch work/note1.txt work/note2.txtで素材を 2 つ作成してください。

find work -name '*.txt'の出力をパイプでxargsに渡し、置換文字列を使って各ファイルを「元の名前の末尾に.bakを足した名前」でコピーしてください。

ls work.bakファイルが 2 つ増えたことを確認してください。

find work -name '*.bak'の出力をxargsに渡し、削除コマンドの前にechoを挟んで、実行される削除コマンドを表示だけして確認してください。

⑤ 表示された対象に問題がなければechoを外して.bakファイルをまとめて削除し、もう一度ls workで消えたことを確認してください。

Linux console
0 / 6 実行済み
Loading Linux Terminal...
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1xargsの役割として正しいものはどれですか?

Q2printf 'a\nb\nc\n' | xargs -n1 echoはどう動きますか?

Q3xargs -I{}{}は何を表しますか?