シンボリックリンクの切れたファイルを探す

今回、ESXi サーバーの導入に伴い、既存の NetBSD サーバーを ESXi ゲストに移行したのですが、その際、あまり参照していないディレクトリに「リンクの切れたシンボリックリンク」が大量に残っているのを発見しました。こいつをまとめて削除しようと思ったのですが、方法が分からず、しばし途方に暮れました。
あるパス名が「リンクの切れたシンボリックリンク」かどうかを確認する方法で、すぐに思いつくのは ls -FL コマンドを使う方法です。例えばここに file_a, symlink_a, symlink_b というパス群があり、symlink_a はリンク先があるが、symlink_b はリンク先が失われているものとしましょう。ls -FL を実行すると、次のようになります。

$ ln -FL
file_a
symlink_a
symlink_b@

-L オプションを付けているにも関わらず、末尾に「@」が表示されるのは、リンクの切れたシンボリックリンクです。しかし、これを find コマンドの自動処理に応用するのは面倒ですし*1、エレガントとは言えません。きっと、何かもっとうまい方法があるはずだ! というわけで、少し調べてみました。
最初は、type*2 や stat コマンドとか探したのですが、解は見つかりません。その後、test コマンドで解決できることが分かりました。例えば find コマンドで、リンクの切れたシンボリックを一覧するには、次のようにします。(-r でなく、-e を使うのが重要です。)

$ find . -exec test -h {} -a \! -e {} \; -print

うまく行っている感じではありますが、盲点がないかどうか、もう少し検証してみようと思います。

盲点、その 1

シンボリックリンク a の先がシンボリックリンク b で、b がさらに c (存在しない)を指しているとき、上述の方法では a も b も対象になってしまいます。これに対応する(判断に選択肢を持たせる)のは、ちょっと面倒そう。。。

*1:シェルスクリプトでも書けば可能でしょうが。

*2:実は、シェルの内部コマンドだった。