ほっしーの技術ネタ備忘録

技術ネタの備忘録です。基本的に私が忘れないためのものです。他の人の役にも立つといいなぁ。

ファイルリストを扱うあれこれ

今回はテキストファイルにファイル名をずらーっと並べていろいろする話。
その tips などを。

基本は find コマンド。

$ find . -type f > filelist

こんな感じでファイルの一覧を作れる。

find にはいろんな機能があって、

$ find . -type f -empty -print > filelist

これで空ファイル(0 byte ファイル)の一覧が作れるし

$ find . -type f -empty -o -print > filelist

これで空じゃないファイルの一覧になる。

"-o" がミソなのだけれども、これは C 言語とかでよくある、
短縮評価のアレと思うのが分かりやすいかも。
empty もしくは print → empty の場合は -o 以降をショートカット → empty じゃない場合のみ print

xargs でファイル名を指定すると、一旦作ったファイルリストを

$ cat filelist | xargs -n 1 -I X find X -empty -print > empty_list
$ cat filelist | xargs -n 1 -I X find X -empty -o -print > not_empty_list

みたいにふるいにかけることもできる。

除外するファイル名を指定したければ

$ find . -name file_name -o -print

と find の機能でやるのがスマートだけど、私は覚えるのが面倒なので

$ find . | grep -v /file_name\$

ってしちゃう。正規表現の方がいろんなパターンに対応できるしね。

二重ループみたいなことがしたいときはこう。

$ echo mysql vpn mail | xargs -n 1 -I X echo /usr/jails/X/var /usr/jails/X/etc | xargs -n 1 -I Y find Y -type f > filelist

みたいな。xargs が空白区切りの 1 行入力もパースしてくれるので、
1つめの xargs では mysql vpn mail で3種類回ってそれぞれで var と etc のパス名を stdout に出してくれる。
それを2つめの xargs で受け取って、find の引数にする。

もしくは、既にファイルリストがあって、それぞれのパス以下を除外したい場合は

$ echo mysql vpn mail | xargs -n 1 -I X echo /usr/jails/X/var /usr/jails/X/etc | xargs -n 1 -I Y grep ^Y input_files > filelist

こんな風に grep の入力としてファイル名を指定すると、Y で始まるファイルを
それぞれ抽出して1ファイルにまとめてくれる。
xargs を使うと grep への stdin を流し込めないので、こういう時は便利な仕様。

シンボリックリンクを除外したいときは

$ cat filelist | xargs -n 1 -I X find X -type l -o -print

xargs で1ファイルずつ名前を取り出して find に食わせる。
シンボリックリンクならそのまま無視して、それ以外なら出力する。

あとは、もっと組み合わせが複雑だったり、ファイル数自体は少ないのであれば、

$ echo /usr/jails/*/etc/cron.d/10-* > filelist

みたいに、シェルに展開させるという手もある。このパターンは、

$ echo *.cc

みたいに ls の代わりに使うこともできる。
ディスクが吹っ飛んだ環境から無理くりサルベージするときに重要なテクニック。

$ echo * | xargs sha256

みたいに本当に ls の代わりにもなる。

$ ls | grep .cc | xargs sha256

って grep を使うよりは

$ echo *.cc | xargs sha256

の方が楽かも。

とかいろいろ。ざざっとスクリプトを書いたり、テンポラリファイルを作れば
もっと平易なコマンドでやれないこともないけど、パズルみたいで面白いよね。