web-dev-qa-db-ja.com

壊れたシンボリックリンクを見つける方法

指し示していないすべてのシンボリックリンクを見つける方法はありますか?

find ./ -type l

すべてのシンボリックリンクを提供しますが、どこかに行くリンクとそうでないリンクを区別しません。

私は現在やっています:

find ./ -type l -exec file {} \; | grep broken

しかし、私はどのような代替ソリューションが存在するのか疑問に思っています。

304
gabe.

タスクにfind -Lを使用することはしないことを強くお勧めします(以下の説明を参照)。これを行う他のいくつかの方法を次に示します。

  • 「純粋なfind」メソッドを使用する場合は、次のようになります。

    find . -xtype l
    

    xtypeは逆参照リンクで実行されるテストです)これはfindのすべてのバージョンで利用できるとは限りませんでも。ただし、他のオプションもあります。

  • findコマンド内からtest -eを実行することもできます。

    find . -type l ! -exec test -e {} \; -print
    
  • 一部のgrepトリックでもfind -Lよりも優れている可能性があります(つまり、safer)。ファイル名を含む出力行):

     find . -type l -exec sh -c 'file -b "$1" | grep -q ^broken' sh {} \; -print
    

引用されたfind -Lトリック solo from commandlinef は見栄えが良くハックに見えますが、非常に危険な落とし穴があります:すべてのシンボリックリンクをたどります。以下に示す内容のディレクトリを検討してください。

$ ls -l
total 0
lrwxrwxrwx 1 michal users  6 May 15 08:12 link_1 -> nonexistent1
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_2 -> nonexistent2
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_3 -> nonexistent3
lrwxrwxrwx 1 michal users  6 May 15 08:13 link_4 -> nonexistent4
lrwxrwxrwx 1 michal users 11 May 15 08:20 link_out -> /usr/share/

そのディレクトリでfind -L . -type lを実行すると、すべての/usr/share/も検索されます(これには非常に時間がかかる場合があります)。1findコマンドが「発信リンクに影響されない」場合は、-Lを使用しないでください。


1 これは、ちょっとした不便さのように見えるかもしれません(コマンドがすべての/usr/shareをトラバースするのに "時間がかかる"だけです)–より深刻な結果になる可能性があります。たとえば、chroot環境について考えてみましょう。メインのファイルシステムのサブディレクトリに存在し、絶対的な場所へのシンボリックリンクを含むことができます。これらのリンクは、「外部」システムでは壊れているように見える可能性があります。これは、chrootに入ると、適切な場所を指すだけだからです。また、一部のブートローダーは、ブートパーティションが/bootとしてマウントされたときに、初期ブートフェーズでのみ意味のある/の下でシンボリックリンクを使用したことを思い出します。

したがって、find -Lコマンドを使用して壊れたシンボリックリンクを見つけ、無害に見えるディレクトリから削除すると、システムが壊れる可能性があります...

380
rozcietrzewiacz

http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gzsymlinksコマンドを使用して、さまざまなシンボリックリンクを識別できます特性の。例えば:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
41
Sam Morris

Rozcietrzewiaczはすでにコメントしているので、find -Lは、シンボリックリンクされたディレクトリに検索を拡張するという予期しない結果をもたらす可能性があるため、最適なアプローチではありません。誰もまだ言及していません

find /path/to/search -xtype l

より簡潔で論理的に同じコマンドです

find /path/to/search -type l -xtype l

これまでに提示された解決策は、別のタイプの破損である循環シンボリックリンクを検出しません。 この質問 は移植性を扱います。要約すると、循環リンクを含む壊れたシンボリックリンクを見つけるポータブルな方法は次のとおりです。

find /path/to/search -type l -exec test ! -e {} \; -print

詳細については、 この質問 または ynform.org を参照してください。もちろん、これらすべての最も信頼できるソースは findutils documentaton です。

33
pooryorick

-Lフラグをコマンドに付けると、grepを削除できます。

$ find -L . -type l

http://www.commandlinefu.com/commands/view/8260/find-broken-symlinks

男から:

 -L      Cause the file information and file type (see stat(2)) returned 
         for each symbolic link to be those of the file referenced by the
         link, not the link itself. If the referenced file does not exist,
         the file information and type will be for the link itself.
9
kwarrick

リンクが壊れているか循環しているかに関係なく別の動作が必要な場合は、findで%Yを使用することもできます。

$ touch a
$ ln -s a b  # link to existing target
$ ln -s c d  # link to non-existing target
$ ln -s e e  # link to itself
$ find . -type l -exec test ! -e {} \; -printf '%Y %p\n' \
   | while read type link; do
         case "$type" in
         N) echo "do something with broken link $link" ;;
         L) echo "do something with cyclic link $link" ;;
         esac
      done
do something with broken link ./d
do something with cyclic link ./e

この例は this post(site deleted) からコピーされます。

参照

7
andy

OPのバージョンのバリエーションである単純な簡単な答え。時々、あなたは単にタイプしたり覚えやすい何かをしたいだけです:

find . | xargs file | grep -i "broken symbolic link"

または、NULLターミネータを処理する必要がある場合:

find . -print0 | xargs -0 file | grep -i "broken symbolic link"
3
trinth

私はこれを私の場合に使用し、壊れたシンボリックリンクを探すディレクトリを知っているので、それはかなりうまくいきます:

find -L $path -maxdepth 1 -type l

私のフォルダには/usr/shareへのリンクが含まれていますが、トラバースしません。クロスデバイスリンクやchrootなどに有効なリンクはまだ落とし穴ですが、私のユースケースではそれで十分です。

2
Iskren

zshユーザーの場合:

rm -v **/*(-@)

from zshユーザーガイドbroken symlinks

2
murlakatamenka

find -L . -type l |xargs symlinksは、リンクが存在するかどうかを、見つかったファイルごとに示します。

1
Alex

これにより、現在のディレクトリにある壊れたシンボリックリンクの名前が出力されます。

for l in $(find . -type l); do cd $(dirname $l); if [ ! -e "$(readlink $(basename $l))" ]; then echo $l; fi; cd - > /dev/null; done

バッシュで動作します。他のシェルについては知らない。

1