IT・技術研修ならCTC教育サービス

サイト内検索 企業情報 サイトマップ

研修コース検索

コラム

WSLで始めるUbuntu

CTC 教育サービス

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes 

第8回 find と xargs を活用してみよう (宮崎悟) 2019年6月

前回はパイプでコマンドに引数を渡す方法について説明しました。
今回は、findとxargsを組み合わせた方法を試してみましょう。

find と xargsの組み合わせ

find と xargsを組み合わせることで、検索したファイルに対して任意のコマンドを一度に実行可能です。xargsは、shellで使用できる最大長に引数を区切ってコマンドを実行します。そのため、複数ファイルを引数に取れるコマンドを実行する際に特に有用です。

まずは簡単な例です。指定した日時(90日)より更新日時が古い通常ファイルを削除します。

$ find /tmp -mtime +90 -t f | xargs rm

この場合、find の -delete オプションを使っても同じ結果が得られます。ただ、xargsを使うことで以下の効果が得られます。

  • find の -deleteの場合
    • ファイルを1つずつ削除する
    • findだけで xargs/rm コマンドを実行する必要がないため、余計なプロセスを使用しない
  • xargs を使う場合
    • ファイルを bashのコマンドライン分まとめて削除する
    • できるだけまとめて削除するため、多数のファイルを処理する場合は効率的

上記例では、find のみを使用するほうが有利です。
xargsへ引数を渡すとき、ファイル名に空白や特殊文字が含まれる場合は、find の -print0 オプション、xargs の -0 オプションを付けなければうまく削除できません。

findで該当するファイルが多いときは、xargs のオプション -P(もしくは--max-procs) 数字で同時起動するプロセス数を指定します。-P オプションを指定しない場合は1プロセス、2以上で指定したプロセス数、0を指定すると出来るだけ多くのプロセスを同時に起動できます。以下は、ファイルの特殊文字を考慮し、最大プロセス数で削除するコマンドとなります。

$ find /tmp -mtime +90 -t f -print0 | xargs -0 -P 0 rm
find と xargsにコマンドを挟む

find と xargs の組み合わせが有効に使えるのは、find で検索して得られたファイル名を加工したい場合などです。
以下は、得られたファイル名からhttpが含まれるファイル名を除外して削除するコマンドです。

$ find /var/log -mtime +90- -type f -name '*.log.*.gz' | grep -v http | xargs rm

上記の場合、90日より前の'*.log.*gz'という通常ファイルをfind で検索し、そこからhttp がファイル名に含まれないファイルを削除します。grep -f FILEで、FILEから除外ファイルに書かれたパターンを削除する方法でも良いでしょう。

また以下のコマンドでは、指定したファイルを検索してソートされた空白区切りの文字列を得られます。

$ find /usr -type f | sort | xargs echo

この出力をみると、以下のように改行が挟まれているのを確認できます。これにより、bashが許しているコマンド列の最大行でxargsが処理を区切っているということが確認できます。

/usr/lib/aspell/iso-8859-7.cset /usr/lib/aspell/iso-8859-8.cmap /usr/lib/aspell/iso-8859-8.cset /usr/lib/aspell/iso-8859-9.cmap
/usr/lib/aspell/iso-8859-9.cset /usr/lib/aspell/ispell /usr/lib/aspell/koi8-r.cmap /usr/lib/aspell/koi8-r.cset /usr/lib/

通常ソートした空白区切りの文字列を用意する場合は、もっと少ないファイルで使用して変数に設定したり、ファイル数が多い場合はファイルに出力する場合が多いです。

xargs を使用できない場合

xargsはとても有用なツールですが、使用できない場面も多いです。

引数を末尾に取らない場合

xargsは、標準入力から得た引数をコマンドの末尾に追加します。そのため、cpやmv などでコピー/移動元として指定する用途には使えません。このような場合は、find の -exec関数を使いましょう。

$ find /var/log -mtime +90 -type f -exec mv {} /var/oldlog
1つしか引数を解釈しないコマンド

例えば、idコマンド(指定したユーザの実IDを表示する)は、1つしかユーザ名を指定することが出来ません。/etc/passwdからユーザ名のみを取得し、全ユーザのid情報を取得するにはどうすればよいでしょうか。この場合は、xargsに-n 1 と取得する引数を指定することで可能です。

$ cut -d: -f1 -s /etc/passwd | xargs -n 1 id
uid=0(root) gid=0(root) groups=0(root)
uid=1(daemon) gid=1(daemon) groups=1(daemon)
uid=2(bin) gid=2(bin) groups=2(bin)
uid=3(sys) gid=3(sys) groups=3(sys)
uid=4(sync) gid=65534(nogroup) groups=65534(nogroup)
uid=5(games) gid=60(games) groups=60(games)
 (以下略)

cutコマンドは、指定したファイルから一部分を取り除くコマンドです。今回は、オプション -d: で区切り文字を「:」とし、区切られた最初の文字列を表示します。-s オプションは区切り文字を含まない行を出力しないオプションになります。これで、xargs はpasswdファイルの最初の項目だけを受け取り、1つの項目ずつidコマンドを実行するようになります。 もちろん、id にオプションを付けて表示することも可能です。

次回予告

さて、次回はシェル変数について説明します。次回をお楽しみに。

 


 

 [IT研修]注目キーワード   Python  UiPath(RPA)  最新技術動向  Microsoft Azure  Docker  Kubernetes