zshは、あらゆる点でbashを凌駕する超強力シェルである。シェルをこれに差し替えるだけで日々の業務が格段に効率化できるので、乗り換えない手はない。MacOSでは標準装備になったらしいが、言うまでもなくlinux他のunix-like OSでも広く使用可能。
かくいう筆者はもう四半世紀zshの愛用者だ。思い立って、zshでfindを(ほぼ)お払い箱にできる話を書くことにした。
ディレクトリを降りていく
findといえば、もちろん指定したディレクトリを起点として、サブディレクトリを下へ下へと辿りながら、所定の条件にあるファイルを探し出し、それに対して何かをしようとするツールである。
findで、拡張子が`.txtなファイルを探すとすると、こんな感じになるだろう。
find . -name '*.txt'
ところが、zshならこう書けば同じことができる。
ls ./**/*.txt
このように**
を重ねると、その階層の深さにかかわらずサブディレクトリ以下の全てのファイルも対象に含まれることになる。findコマンドの一番根幹的な機能のお株を奪っている。zshすごくね?
「ファイル修飾子」でファイルを絞り込む
ワイルドカードに加えてzshのパス指定には「ファイル修飾子」というものを追加することができ、これによって複雑な条件指定が可能となっている。
変更日時でファイルを絞り込む
たとえば、findならfind . -mtime -1
とでもすべきところ、zshならこう書けばできる。
ls ./**/*(mh-24)
zshの(mh-24)
は、「24時間以内に変更されたファイル」にマッチする。なお、findがサポートする時間の単位は「分」と「日」のみだが、zshのファイル修飾子は月・週・時間・分・秒に対応している。反面「日」には対応していないようだ……。
同様に、-ctime -1
およびatime -1
は、zshではそれぞれ(ch-24)
および(ah-24)
である。
ファイルタイプでファイルを絞り込む
findならfind . -type d
とでもすべきところ、zshならこう書けばできる。
ls ./**/*(/)
同様に、対象を通常ファイル・シンボリックリンク・実行ファイルに絞ることもできる。対応する文字はそれぞれ.
、@
、*
である。
アクセス権でファイルを絞り込む
findならfind . -perm 600
とでもすべきところ、zshならこう書けばできる。
ls ./**/*(f600)
まだまだいろいろできる
この他、ファイルサイズやファイルオーナーでもファイルを絞りこめる。
これらのオプションは同時に指定することもできる。例えばsuzukiさんが持っている実行可能なシェルスクリプトだけを拾いたければ*.sh(*u:suzuki:)
などとすればいい。OR条件にも対応可能で、例えば*.sh(u:suzuki:,u:yamada:)
とすれば、suzukiさんかyamadaさんのどちらかが持っているシェルスクリプトを拾える。
そろそろしんどくなってきたので、あとはman zshexpn
に任せよう。
選びだしたファイルに対して何かをする
上記のように柔軟な条件設定で探してきたファイルに対して、forループを利用していろいろな処理をかけることができる。
たとえば、findを使った次のようなオペレーションを考えてみよう。
find . -name '*.txt' -exec wc -l {} \;
zshならこんな感じで処理できる。括弧が多いが、bashのループよりもシンプルで分かりやすいと思う。
foreach a (./**/*.txt) { wc -l $a }
おわりに
まだまだ終わりじゃないんだよ、zshの優れた点は。
しかし、この**
記法が使えるだけでも、zshに乗り換える理由としては十分じゃないか?