「コマンドの引数にファイル一覧を渡したいけど、数が多すぎてエラーになる」
xargsは、標準入力から受け取ったデータをコマンドの引数として渡すコマンドです。findやgrepの出力をそのまま別のコマンドに引き渡せるため、ファイルの一括処理やログの一括検索など、日常的なサーバー管理作業を大幅に効率化できます。
この記事では、xargsの基本的な使い方から、スペースを含むファイル名の安全な処理、並列実行、find -execとの使い分けまで、実務で必要な知識を網羅します。
なぜxargsが必要なのか?~パイプだけでは解決できない場面~
Linuxでは、コマンドの出力をパイプ(|)で次のコマンドに渡すのが日常的です。しかし、パイプが渡すのは「標準入力」であって「引数」ではありません。この違いが問題になる典型例を見てみましょう。
# これは動かない(rmは標準入力を受け付けない) find /tmp -name "*.log" | rm # xargsを使えば、findの出力をrmの「引数」として渡せる find /tmp -name "*.log" | xargs rm
xargsは、この「標準入力 → 引数」の変換を担うコマンドです。
基本的な使い方
1. find | xargs の基本パターン
最も使用頻度が高いのが、findの出力をxargsで別のコマンドに渡すパターンです。# /var/log 配下の .log ファイルを一覧表示 find /var/log -name "*.log" | xargs ls -l # 30日以上前の一時ファイルを削除 find /tmp -type f -mtime +30 | xargs rm -f
2. -I {} でプレースホルダを指定する
デフォルトのxargsは、引数をコマンドの末尾に追加します。引数を任意の位置に挿入したい場合は -I {} を使います。# ファイルをバックアップディレクトリにコピー find /etc -name "*.conf" | xargs -I {} cp {} /backup/ # ファイル名の前後に文字を追加してリネーム ls *.txt | xargs -I {} mv {} old_{}
3. -print0 と -0 でスペースを含むファイル名を安全に処理する
xargsの最大の落とし穴は、スペースを含むファイル名の扱いです。デフォルトではスペースが区切り文字として解釈されるため、「my file.txt」が「my」と「file.txt」の2つに分割されてしまいます。# 安全な書き方(NULL文字で区切る) find /home -name "*.txt" -print0 | xargs -0 rm -f # NG(スペースを含むファイル名が分割される) find /home -name "*.txt" | xargs rm -f
※ 本番環境でfind | xargsを使う場合は、常に -print0 | xargs -0 の組み合わせを使うのが鉄則です。
4. echo や cat からの入力
findだけでなく、echoやcatの出力もxargsに渡せます。# スペース区切りの文字列を1つずつ処理 echo "server1 server2 server3" | xargs -n 1 ping -c 1 # ファイルに書かれたホスト一覧に対してコマンドを実行 cat hosts.txt | xargs -I {} ssh {} "uptime"
5. -n で引数の個数を制限する
-n オプションで、1回のコマンド実行に渡す引数の数を制限できます。# 引数を2個ずつに分割して実行 echo "a b c d e f" | xargs -n 2 echo # 実行結果 a b c d e f
応用・実務Tips
1. grep -l | xargs sed -i で複数ファイルを一括置換
設定ファイルの一括変更は、サーバー管理で頻繁に発生する作業です。# 「old_server」を含むファイルを検索し、一括で「new_server」に置換 grep -rl "old_server" /etc/ | xargs sed -i "s/old_server/new_server/g" # 置換前に対象ファイルを確認(安全策) grep -rl "old_server" /etc/ | xargs ls -l
※ 本番環境では、置換前に必ず対象ファイルを確認してください。
2. find + xargs vs find -exec の使い分け
findで見つけたファイルにコマンドを実行する方法は2つあります。# xargs方式(高速:コマンドをまとめて実行) find /var/log -name "*.log" -print0 | xargs -0 gzip # -exec方式(1ファイルずつ実行) find /var/log -name "*.log" -exec gzip {} \; # -exec +方式(xargsと同様にまとめて実行) find /var/log -name "*.log" -exec gzip {} +
・-exec \;方式:1ファイルずつコマンドを起動するため遅いが、確実に1つずつ処理できる
・-exec +方式:xargsと同様にまとめて実行。外部コマンドへのパイプが不要な分シンプル
基本的にはxargs方式か -exec + 方式を使い、ファイル名にスペースが含まれる可能性がある場合は -print0 | xargs -0 が最も安全です。
3. -P で並列実行する
-P オプションで、複数のプロセスを同時に実行できます。CPUやネットワークがボトルネックにならない処理では、大幅な時間短縮が可能です。# 4並列でgzip圧縮を実行 find /var/log -name "*.log" -print0 | xargs -0 -P 4 gzip # 8並列で画像をリサイズ(ImageMagick) find /images -name "*.jpg" -print0 | xargs -0 -P 8 -I {} convert {} -resize 800x600 {}
4. -p で確認プロンプト付き実行、-t で実行コマンドを表示
削除や変更を伴う操作では、実行前の確認が重要です。# 実行前にy/nの確認プロンプトを表示 find /tmp -name "*.bak" | xargs -p rm -f # 実行するコマンドを標準エラー出力に表示(デバッグ用) find /var/log -name "*.log" | xargs -t gzip
トラブルシュート・エラー対処
1. ファイル名にスペースや特殊文字がある場合の問題
xargsのデフォルトでは、スペース・タブ・改行が区切り文字です。ファイル名にこれらが含まれると、意図しない分割が発生します。# 問題の例:"my report.txt" が "my" と "report.txt" に分割される echo "my report.txt" | xargs rm # rm: cannot remove 'my': No such file or directory # rm: cannot remove 'report.txt': No such file or directory # 解決策:-print0 と -0 を組み合わせる find /home -name "*.txt" -print0 | xargs -0 rm -f # find以外の入力では -d でデリミタを改行に変更する ls | xargs -d '\n' rm -f
2. 「Argument list too long」エラーの回避
ワイルドカード展開でファイル数が多すぎると、シェルの引数長制限に引っかかります。xargsを使うことでこのエラーを回避できます。# エラーになるケース(ファイル数が多すぎる) rm /tmp/logs/*.log # -bash: /bin/rm: Argument list too long # xargsで回避(自動的に分割して実行) find /tmp/logs -name "*.log" | xargs rm -f # 現在のシステムの引数長制限を確認 getconf ARG_MAX
3. xargsに渡すコマンドでリダイレクトを使う方法
xargsの中でリダイレクト(>や>>)を直接使うことはできません。シェルがxargsの実行前にリダイレクトを解釈してしまうためです。# NG(リダイレクトがxargsではなくシェルに解釈される) find /var/log -name "*.log" | xargs head -1 > result.txt # OK(sh -c でサブシェルを使う) find /var/log -name "*.log" | xargs -I {} sh -c "head -1 {} >> result.txt" # OK(ファイルごとに別のファイルに出力) find /var/log -name "*.log" | xargs -I {} sh -c "wc -l {} > {}.count"
4. 入力が空の場合の挙動
xargsに空の入力が渡された場合、GNU版(Linux標準)ではコマンドを実行しません。ただし、明示的に制御したい場合は --no-run-if-empty(-r)を付けます。# 入力が空ならコマンドを実行しない(GNU xargsではデフォルトの動作) find /tmp -name "*.nonexistent" | xargs --no-run-if-empty rm -f # 短縮形 find /tmp -name "*.nonexistent" | xargs -r rm -f
本記事のまとめ
xargsの主要な使い方を一覧にまとめます。| やりたいこと | コマンド |
|---|---|
| findの結果にコマンドを実行 | find パス 条件 | xargs コマンド |
| スペースを含むファイル名を安全に処理 | find パス 条件 -print0 | xargs -0 コマンド |
| 引数を任意の位置に挿入 | find パス 条件 | xargs -I {} コマンド {} |
| 引数の個数を制限して実行 | find パス 条件 | xargs -n 数 コマンド |
| 複数ファイルを一括置換 | grep -rl "文字列" パス | xargs sed -i "s/旧/新/g" |
| 並列実行で処理を高速化 | find パス 条件 -print0 | xargs -0 -P 並列数 コマンド |
| 確認プロンプト付きで実行 | find パス 条件 | xargs -p コマンド |
| 実行コマンドを表示 | find パス 条件 | xargs -t コマンド |
| リダイレクトを使う | find パス 条件 | xargs -I {} sh -c "コマンド {} > 出力先" |
| Argument list too longを回避 | find パス -name "パターン" | xargs rm -f |
xargsを使いこなして、日々のサーバー管理を効率化しませんか?
xargsは、findやgrepと組み合わせることで真価を発揮するコマンドです。こうしたコマンド連携の「型」を身につけることで、作業スピードが大きく変わります。
ネットの切れ端の情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
登録10秒/自動返信でDL/合わなければ解除3秒
