xargsは、他のコマンドの出力を、別のコマンドの「引数」として渡すためのコマンドです。findで見つけたファイルの一覧を、まとめてrmやgrepに渡して一括処理する、というのが定番の使い方です。パイプは「前のコマンドの出力を次のコマンドの標準入力として渡す」仕組みですが、rmやcpのような多くのコマンドは標準入力ではなく「引数」でファイル名を受け取るため、そのままパイプでは渡せません。この橋渡しをするのがxargsです。
ただし、xargsには有名な落とし穴があります。ファイル名にスペースが含まれていると、既定の設定では1つのファイルが2つの引数に分割されてしまうのです。この記事では、実機のLinux(WSLのDebian)でこの罠を実際に再現し、正しい対処法まで整理します。
xargsは、標準入力を「引数」に変換して次のコマンドに渡します。- 基本形は
find ... | xargs コマンド(見つけたファイルをまとめて処理)。 - スペースを含むファイル名は、既定では2つの引数に分割されてしまいます。
- 対策は
find ... -print0 | xargs -0(NUL文字区切り)です。 - 複雑な組み立てには
-I{}(プレースホルダ)を使います。 - 入力が空のときは、既定ではコマンド自体が実行されません。
ファイルを探すfindコマンド、パイプの基本リダイレクトとパイプ、削除コマンドの基本cp・mv・rmもあわせて参考になります。
基本:findの結果をxargsに渡す
findで見つけたファイルの一覧(1行1ファイル)を、xargsを通すことで1つのコマンドの引数としてまとめて渡すことができます。
# find の結果を echo の引数としてまとめて渡す find sub -name "*.txt" | xargs echo "見つかった:" # 見つかった: sub/normal.txt sub/another.txt sub/my file.txt # .log ファイルをまとめて削除 find . -name "*.log" | xargs rm # grep と組み合わせて、複数ファイルの中身をまとめて検索 find . -name "*.txt" | xargs grep "エラー"
実機でも、find sub -name "*.txt" | xargs echoで、見つかった複数のファイルパスが1回のechoコマンドの引数としてまとめて渡されることを確認しました。パイプだけでは「標準入力」として渡るだけで、rmやgrepのようなコマンドの引数として展開されるわけではありません。xargsを挟むことで、この変換が行われます。
【最重要】スペース入りファイル名で壊れる罠
xargs最大の落とし穴です。標準入力を「空白や改行」で区切って引数にするという既定の動作のため、ファイル名自体にスペースが含まれていると、1つのファイルが2つの引数に分割されてしまいます。
# 「my file.txt」という、スペースを含む名前のファイルがあるとする ls sub/ # another.txt my file.txt normal.txt # xargs -n1(1つずつ処理)で確認すると… find sub -name "*.txt" | xargs -n1 echo "対象:" # 対象: sub/my ← "my file.txt" が2つに割れてしまった! # 対象: file.txt # 対象: sub/normal.txt # 対象: sub/another.txt
実機で、スペースを含むmy file.txtというファイルを対象にfind | xargs -n1を実行したところ、本来1つのファイルであるはずのsub/my file.txtが、sub/myとfile.txtというまったく別の2つの引数に分裂しました。xargsは既定で空白(スペース・タブ・改行)を区切り文字として扱うため、ファイル名の中のスペースまで「区切り」だと誤解してしまうのです。この状態でrmなどを実行すると、「file.txt」という存在しないファイルを消そうとしてエラーになったり、意図しないファイルを操作したりする事故につながります。日本語のファイル名やWindowsから持ち込んだファイルなど、スペースを含む名前は実務でも頻繁に登場するため、この罠は非常に重要です。
対策:find -print0 と xargs -0
この罠を回避する正式な方法が、findの-print0とxargsの-0の組み合わせです。区切り文字を、ファイル名に絶対使われないNUL文字(\0)に変えることで、スペースを含む名前でも安全に扱えます。
# -print0: 区切りを改行ではなく NUL 文字にする # -0 : xargs 側もその NUL 区切りで読む find sub -name "*.txt" -print0 | xargs -0 -n1 echo "対象(0区切り):" # 対象(0区切り): sub/my file.txt ← 1つの引数として正しく扱われた # 対象(0区切り): sub/normal.txt # 対象(0区切り): sub/another.txt # 実際の削除でも同様に使う(スペース入りファイルも安全に削除できる) find . -name "*.log" -print0 | xargs -0 rm
実機でも、-print0と-0の組み合わせに変えると、sub/my file.txtが1つの正しい引数として扱われました。さらに、実際にこの組み合わせで.logファイルを削除するテストを行い、対象のファイルだけが正しく消え、他のファイルは残ることも確認しています。「findとxargsを組み合わせるときは、常に-print0+-0をセットで使う」と覚えておけば、スペース入りファイル名の事故を防げます。ファイル名にスペースが含まれないと分かっている場合を除き、この組み合わせを基本形にするのが安全です。
-Iプレースホルダで複雑なコマンドを組み立てる
xargsに渡した値を、コマンドの途中や複数箇所で使いたいときは、-Iでプレースホルダ(目印)を指定します。{}がよく使われる目印です。
# {} の部分に、渡された値が展開される
echo -e "a.txt\nb.txt" | xargs -I{} echo "cp {} backup/{}"
# cp a.txt backup/a.txt
# cp b.txt backup/b.txt
# 実際にコピーを実行する例
find . -name "*.txt" | xargs -I{} cp {} /path/to/backup/
実機でも、-I{}を使うと{}の部分に渡された値がそのまま展開され、cp a.txt backup/a.txtのように同じ値をコマンドの複数箇所で使うことができました。単純に末尾へ引数を並べるだけの-n1と違い、-Iを使えば「コピー元とコピー先の両方に同じファイル名を使う」といった、より複雑な組み立てが可能になります。
入力が空のときはコマンドが実行されない
意外と知られていないのが、標準入力が空のとき、xargsは既定でコマンド自体を実行しないという仕様です。「対象が0件なら何もしない」という安全な挙動ですが、強制的に実行させたい場面では-r(の逆の意味の明示)に注意が必要です。
# 入力が空だと、xargs はコマンドを実行しない echo -n "" | xargs echo "実行された:" # (何も出力されない=実行されていない) # find で対象が1件も見つからなかった場合も同様 find . -name "*.nonexistent" | xargs rm # 何も実行されず、rm も呼ばれない(安全)
実機でも、空の入力をxargs echoに渡すと何も出力されず、echoコマンド自体が呼び出されていないことを確認しました(もし普通にechoしていれば実行された:とだけ出力されるはずです)。この仕様のおかげで、「findで対象が0件だったのに、空の引数でrmが誤って実行される」といった事故が起きません。find | xargs rmという組み合わせが安全に使えるのは、この「入力が空なら何もしない」というxargsの防御的な設計のおかげです。
主な書き方一覧
xargsでよく使うオプションをまとめます。
| 書き方 | 働き |
|---|---|
find ... | xargs コマンド |
見つけたファイルをまとめて処理 |
find ... -print0 | xargs -0 |
スペース入りファイル名でも安全 |
xargs -n 数 |
指定した個数ずつコマンドを実行 |
xargs -I{} |
プレースホルダで複雑な組み立て |
xargs -p |
実行前に確認プロンプトを出す |
| 入力が空 | 既定ではコマンドを実行しない |
よくある失敗
スペース入りファイル名で処理が壊れる
既定では空白区切りのため分裂します。find -print0 | xargs -0で対処します。
パイプだけで引数を渡そうとする
find ... | rmでは動きません。rmは標準入力ではなく引数でファイル名を受け取るため、xargsが必要です。
rmなど破壊的な操作をいきなり実行する
xargs echoで対象を確認してから、コマンドを差し替えるのが安全です。
1つの値を複数箇所で使いたいのに-n1だけで済ませる
-I{}プレースホルダを使えば、同じ値をコマンドの複数箇所で使い回せます。
find -print0を忘れて-0だけ付ける
両方セットで使う必要があります。片方だけでは区切りの形式が合いません。
よくある質問
rmやcpのような多くのコマンドは標準入力ではなく引数でファイル名を受け取るため、findで見つけたファイルをまとめて処理したいときにfind ... | xargs コマンドという形でよく使われます。xargsは既定で空白を区切り文字として扱うため、スペースを含むファイル名が2つの引数に分割されてしまいます。実機でも、「my file.txt」が「my」と「file.txt」に分裂することを確認しています。対策はfind ... -print0 | xargs -0のように、区切り文字をNUL文字に変える方法です。-print0はfindの出力の区切りをNUL文字にし、-0はxargs側もその区切りで読み込む指定です。片方だけでは区切りの形式が一致しないため、スペース対策になりません。実機でも、両方を組み合わせて初めてスペース入りファイル名が正しく扱えることを確認しています。-I{}でプレースホルダを指定します。xargs -I{} cp {} backup/{}のように書くと、渡された値が{}の部分すべてに展開されます。実機でも、コピー元とコピー先の両方に同じファイル名が正しく展開されることを確認しています。まとめ
xargsは標準入力を引数に変換し、次のコマンドへ渡します。- 基本形は
find ... | xargs コマンドで、まとめて一括処理できます。 - スペース入りファイル名は既定では分裂します。
find -print0 | xargs -0で対処します。 - 複雑な組み立ては
-I{}プレースホルダを使います。 - 入力が空ならコマンド自体が実行されない安全設計です。
xargsは、findと組み合わせることで真価を発揮する強力なコマンドです。「スペース入りファイル名は-print0+-0」という一点さえ押さえておけば、ファイル名にまつわる事故を避けながら、一括処理を安全かつ効率的に行えるようになります。
- grep(文字列検索)
- find(ファイル検索)
- sed(置換・行編集)
- awk(列抽出・集計)
- chmod(パーミッション)
- tar(圧縮・解凍)
- リダイレクトとパイプ
- ps・kill(プロセス管理)
- 環境変数とPATH
- ln(シンボリックリンク)
- cp・mv・rm(コピー/移動/削除)
- history(コマンド履歴)
- curl(HTTP通信・API)
- jq(JSON処理)
- vim(基本操作・終了方法)
- cron・crontab(定期実行)
- sort・uniq・wc(並べ替え/集計)
- xargs(一括処理)
- chown・chgrp(所有者/グループ変更)
- diff(ファイル比較)
- du・df(ディスク使用量)
- よく使うコマンドまとめ
- cd(ディレクトリ移動)

