今回はテキストファイルにファイル名をずらーっと並べていろいろする話。
その 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
の方が楽かも。
とかいろいろ。ざざっとスクリプトを書いたり、テンポラリファイルを作れば
もっと平易なコマンドでやれないこともないけど、パズルみたいで面白いよね。