kei0425tan’s blog

技術的なことを主に

find & xargs

linuxコマンドラインで作業していると、ある特定のファイル全てをなんとかしたいことってよくありますね。
findが便利なんですが、ついつい使い方を忘れてしまいます。
なので、メモ

findについて

主要オプション

たくさんオプションありますが、必要なのは以下ぐらいで十分でしょう。

  • -name 指定したファイル名の場合真になります。正規表現ではなく、ファイル名のワイルドカードで指定します。ただし、普通に指定してしまうと、シェルに食われてしまため、''で括って指定するといいでしょう。

* 任意の0文字以上
? 任意の1文字

  • -type 指定したファイルタイプの場合真になります。

d ディレクト
f ファイル
l シンボリックリンク

  • -maxdepth 再帰して検索する深さを指定します。
  • -ls 表示をls -lと同じ形式で出力します。
  • -size ファイルサイズが指定以上の場合真になります。単位省略はブロック。kはキロバイトです。
  • -atime, -ctime, -mtime それぞれ、n時間以内にアクセス、ステータス変更、修正した場合真になります。
  • ( ) ! -o 演算子。(はシェルに食われてしまうため、\(で指定します。-oはorです。省略でandになります。

短絡評価を行うため、通常は偽があればそこから後ろは評価しません。-o指定されている場合は真の場合は後ろは評価しません。

見つけるだけならこれくらいでほとんど十分かと思います。
あとは、-execと-okで任意のコマンドを実行できます。(-okは問い合わせしてきてY/yで実行します)

-execの場合は、;まで(シェルに食われるため実際に指定するのは\;)を1行のコマンドとして実行します。
{}は見つけたファイル名で置き換えます。

実行例

コマンドが複雑になりがちなため、まずは、ファイルを確認。その後、コマンドを確認してから実際にコマンドを実行するのがよいと思います。

emacsのバックアップファイルを確認する。

find . -name '*~'

emacsのバックアップファイルを削除する。(のがうまく行くかどうか事前に確認する。)

find . -name '*~' -exec echo echo rm {} \;

emacsのバックアップファイルを実際に削除する。

find . -name '*~' -exec echo rm {} \;

エビデンス的なものが必要な場合は、以下のように実行するとよいかと思います。

find . -name '*~' -exec echo echo rm {} \; > command.sh
sh command.sh

ファイルの確認を行う時点でファイルを作成して、sedなどで置き換えるのも一つの手です。

xargsについて

find -execで大体なんでもできてしまうのですが、-execの仕組みとして、1ファイル1コマンドを実行してしまいます。
該当するファイルが数千ある場合などは、数千回シェルが実行されてしまいます。
それだと効率が悪いため、xargsコマンドができました。

基本的には以下のように利用します。

find . -name '*~' | xargs rm

ここでも、echoをはさむとどういうコマンドが実行されるのかがよくわかります。

find . -name '*~' | xargs echo rm

簡単にいうと、xargs は入力をまとめて指定したコマンドの引数に渡します。
それにより、シェルの呼び出し回数が最低限になります。
引数の上限を超える場合には、いい感じに複数回実行してくれます。