Solution 1 :
Utilisez simplement namei
:
$ namei d
f: d
l d -> c
l c -> b
l b -> a
d a
Solution 2 :
readlink -e <link>
lien de lecture [OPTION]... FICHIER
- -e, --canonicalize-existing
canoniser en suivant chaque lien symbolique dans chaque composant du nom donné de manière récursive, tous les composants doivent exister
$ mkdir testlink
$ cd testlink
[email protected]:~/testlink$ ln -s c b
[email protected]:~/testlink$ ln -s b a
[email protected]:~/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
[email protected]:~/testlink$ echo foo > c
[email protected]:~/testlink$ cat a
foo
[email protected]:~/testlink$ readlink -e a
/home/pjb/testlink/c
note :readlink a par lui-même renvoie b
note #2 :avec find -l, un utilitaire pour lister les chaînes peut 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.
[email protected]:~/testlink$ ln -sf a c
[email protected]:~/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
[email protected]:~/testlink$ readlink -e a
[email protected]:~/testlink$ # (note: no output)
Solution 3 :
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 nécessite stat(1)
qui peut ne pas être présent sur certains systèmes.
Il échouera si les noms contiennent des backticks, des guillemets simples ou "->". Il reste coincé dans une boucle avec des boucles de liens symboliques (cela pourrait être résolu en utilisant un tableau associatif dans Bash 4). Il exporte une variable appelée "chaîne" sans se soucier de savoir si elle est déjà utilisée.
Il peut y avoir d'autres problèmes avec cela.
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
}