FreeBSD システムのディスク全体から特定の記述を探したい場合、ありますよね。 例えば IPv6 プレフィックスが変わったので全体の設定を変えなきゃいけない時とか。どこに設定したっけ…?みたいな。
そんな時はざっくり全体から検索してしまいましょう。
$ sudo find / -path '*/dev/*' -prune -o -path '*/proc/*' -prune -o -path '*/var/log/*' -prune -o -name '*.log' -prune -o -path '*/basejail/*' -prune -o -type f -print0 | sudo xargs -0 grep "search target" | tee result.txt
…いやなっげぇよ!!
まぁ、以前同じ内容の記事を書いたときのやり方そのままですね。 hoshizuki.hateblo.jp
やってることは、 find
を /
起点で実行して、別に探さなくてもいいパスを -path '*/var/log/*' -prune -o
でどんどん落としています。 -o
つまり OR の短絡評価によって途中でマッチしたパスを間引いていって、最後に残ったものを -print0
します。
前回の記事と違って、最近は -path
を使ってワイルドカードでの一致にしていますね。正規表現面倒で嫌いなので。
あとはおなじみ xargs
からの grep
です。まぁまぁ単純でシンプルなコマンドです。
出力結果は stdout
でリアルタイムに眺めつつ、一応ファイルにもロギングしているおまけ付き。
なお、前回の記事に書いた通り、ディレクトリ名にスペースが含まれていると xargs
につっこんだときに分解されて悲しい目に遭うので、 -print0
で出して xargs -0
で受けます。
シンプルだけれども、できればマウントポイントごとフィルタ除外したいっていうか、 grep
の前の find
は一応全ディレクトリを見に行くので、その無駄すらも何とかしたい。
そこでこんな改良。
$ ls / | grep -v -e home -e sys -e mnt | sudo xargs -n 1 -I {} find {} -type f | sudo xargs grep "search target" | tee ~/grep_result.txt
/
直下のディレクトリ一覧を ls
で取得して、 grep
でざっくりフィルタリング。
/home
とか /sys
とか /mnt
とか探しても仕方ないマウントポイントはいくつもあります。
ここでは -v
で grep
の論理を反転します。 -e
で検索対象を複数書くのと組み合わせると、「いずれにもマッチしないもの」のみを抽出できます。
んでそれを xargs
で順に find
に投げて、全ファイルの一覧から grep
します。
しかし、特に ezjail でありがちな、いろんな所でいろんな所を nullfs でマウントしてると、これだけだとまだ弱い。マウントポイントはイマドキ /
だけじゃない。
そんな訳でこんなパターンが最近のお気に入り。
$ mount -p | awk '{print $2}' | grep -v -e '/basejail$' -e '/dev$' -e '/dev/fd$' -e '/proc$' -e '/home$' -e '/var/ports$' -e '^/mnt/external$' | sudo xargs -n 1 -I {} find {} -mount -path '/usr/src/*' -prune -o -path '/usr/ports/*' -prune -o -path '*/basejail/*' -prune -o -path '*/var/log/*' -prune -o -type f -print0 | sudo xargs -0 grep 'search_target' | tee result.log
さらに長くなったナァ……
mount -p
で現在のマウント状況を fstab
フォーマットでダンプしてくれます。 awk
で第2フィールド、つまりマウントポイントのみのリストにして、これをさっきの例のように grep -v -e ... -e ...
でフィルタします。最初の grep
ではマウントポイントしか出てこないので、例えば末尾のディレクトリ名などでパターンパッチングします。
次は同じように xargs
からの find
ですが、最初に -mount
を付けるのがミソ。これでマウントポイントになってるディレクトリで検索を打ち切ります。そのマウントポイントが検索対象ならば別途 xargs
に入ってくるレコードによって補完されますし、対象外ならそのまま無視になります。
後は同じように -path '...' -prune -o
でマウントポイント以外のフィルタリングをしてから、 xargs
で grep
に流して終わり。
これでだいぶ高速になりました。コマンドは長いけどなー……