web-dev-qa-db-fra.com

Comment lister les chaînes de liens symboliques?

Étant donné cet exemple:

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

Si j'exécute:

ls -l d

Il montrera:

d -> c

Existe-t-il un moyen pour ls ou toute autre commande linux d'afficher d -> c -> b -> a au lieu?

36
Kalecser

Utilisez simplement namei:

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

readlink -e <link>

readlink [OPTION] ... FICHIER

  • -e, --canonicalize-existant
    canoniser en suivant chaque lien symbolique dans chaque composant du nom donné récursivement, tous les composants doivent exister
$ 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

remarque: le lien de lecture a renvoie lui-même b

note # 2: avec find -l, un utilitaire pour lister les chaînes pourrait facilement être écrit en Perl, mais doit également être suffisamment intelligent pour détecter les boucles

readlink ne produira rien si vous avez une boucle. C'est mieux que de rester coincé, je suppose.

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

Voici une fonction récursive dans 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; }

Sur plusieurs lignes:

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
}

Exemples:

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

Il requiert stat(1) qui peut ne pas être présent sur certains systèmes.

Il échouera si les noms contiennent des guillemets, des guillemets simples ou "->". Il est coincé dans une boucle avec des boucles de lien symbolique (cela pourrait être résolu en utilisant un tableau associatif dans Bash 4). Il exporte une variable appelée "chaîne", qu'elle soit déjà utilisée ou non.

Il peut y avoir d'autres problèmes.

Modifier:

Correction d'un problème avec certains liens symboliques relatifs. Certains ne fonctionnent toujours pas, mais la version ci-dessous ne nécessite pas que la cible du lien existe.

Ajout d'une version qui utilise 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
}

Vous pouvez simplement post-traiter la sortie de namei avec quelque chose comme awk ou grep pour obtenir juste les lignes que vous voulez:

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

ou

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