web-dev-qa-db-ja.com

シンボリックリンクチェーンをリストする方法は?

この例を考えると:

mkdir a
ln -s a b
ln -s b c
ln -s c d

私が実行すると:

ls -l d

表示されます:

d -> c

代わりにlsまたは他のLinuxコマンドがd -> c -> b -> aを表示する方法はありますか?

36
Kalecser

nameiを使用するだけです:

$ namei d
f: d
 l d -> c
   l c -> b
     l b -> a
       d a
70
Mike

readlink -e <link>

readlink [オプション] ...ファイル

  • -e、-canonicalize-existing
    指定された名前のすべてのコンポーネントのすべてのシンボリックリンクを再帰的にたどることによって正規化し、すべてのコンポーネントが存在している必要があります
$ mkdir testlink
$ cd testlink
pjb@pjb-desktop:~/testlink$ ln -s c b
pjb@pjb-desktop:~/testlink$ ln -s b a
pjb@pjb-desktop:~/testlink$ ls -l 
total 0
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 a -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 b -> c
pjb@pjb-desktop:~/testlink$ echo foo > c
pjb@pjb-desktop:~/testlink$ cat a
foo
pjb@pjb-desktop:~/testlink$ readlink -e a
/home/pjb/testlink/c

注:readlink a自体はbを返します

注2:チェーンを一覧表示するユーティリティは、find -lと一緒にPerlで簡単に作成できますが、ループを検出するのに十分スマートでなければなりません。

ループがある場合、readlinkは何も出力しません。これは行き詰まるよりはましだと思います。

pjb@pjb-desktop:~/testlink$ ln -sf a c
pjb@pjb-desktop:~/testlink$ ls -l 
total 0
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 a -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 b -> c
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:03 c -> a
pjb@pjb-desktop:~/testlink$ readlink -e a
pjb@pjb-desktop:~/testlink$ # (note: no output)
18
Paul

Bashの再帰関数を次に示します。

_chain() { export chain; local link target; if [[ -z $chain ]]; then chain="$1"; fi; link=$(stat --printf=%N $1); while [[ $link =~ \-\> ]]; do target="${link##*\`}"; target="${target%\'}"; chain+=" -> $target"; chain "$target"; return; done; echo "$chain"; unset chain; }
_

複数行で:

_chain() {
    export chain
    local link target
    if [[ -z $chain ]]
    then
        chain="$1"
    fi
    link=$(stat --printf=%N "$1")
    while [[ $link =~ \-\> ]]
    do
        target="${link##*\`}"
        target="${target%\'}"
        chain+=" -> $target"
        if [[ ! $target =~ / && $1 =~ / ]]
        then
            target="${1%/*}/$target"
        fi
        chain "$target"
        return
    done
    echo "$chain"
    unset chain
}
_

例:

_$ chain d
d -> c -> b -> a
$ chain c
c -> b -> a
$ chain a
a
_

一部のシステムには存在しないstat(1)が必要です。

名前にバッククォート、一重引用符、または "->"が含まれていると失敗します。これは、symlinkループのあるループでスタックします(これは、Bash 4の連想配列を使用して解決できます)。すでに使用されているかどうかに関係なく、「チェーン」と呼ばれる変数をエクスポートします。

その他の問題がある可能性があります。

編集:

いくつかの相対シンボリックリンクの問題を修正しました。一部はまだ機能しませんが、以下のバージョンではリンクのターゲットが存在する必要はありません。

Readlinkを使用するバージョンを追加しました:

_chain ()
{
    export chain;
    local target;
    if [[ -z $chain ]]; then
        chain="$1";
    fi;
    target=$(readlink "$1");
    while [[ $target ]]; do
        chain+=" -> $target";
        if [[ ! $target =~ / && $1 =~ / ]]
        then
            target="${1%/*}/$target"
        fi
        chain "$target";
        return;
    done;
    echo "$chain";
    unset chain
}
_

Nameiの出力をawkgrepなどで後処理して、必要な行だけを取得できます。

namei d | awk '$1=="l"'

または

namei d | egrep -e "->"
0
Tony