É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?
Utilisez simplement namei
:
$ namei d
f: d
l d -> c
l c -> b
l b -> a
d a
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)
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 "->"