Como listar cadeias de links simbólicos?

31

Dado este exemplo:

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

Se eu executar:

ls -l d

Ele mostrará:

d -> c

Existe uma maneira de ls ou qualquer outro comando linux exibir d -> c -> b -> a ?

    
por Kalecser 23.02.2010 / 17:23

3 respostas

58

Use apenas namei :

$ namei d
f: d
 l d -> c
   l c -> b
     l b -> a
       d a
    
por 22.11.2011 / 11:03
16

readlink -e <link>

readlink [OPTION]... FILE

  • -e, --canonicalize-existing
    canonicalize by following every symlink in every component of the given name recursively, all components must exist
$ 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

nota: readlink a por si só retorna b

nota # 2: junto com o find -l, um utilitário para listar as cadeias pode ser facilmente escrito em perl, mas também deve ser inteligente o suficiente para detectar loops

readlink não produzirá nada se você tiver um loop. Isso é melhor do que ficar preso, suponho.

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)
    
por 23.02.2010 / 17:51
3

Aqui está uma função recursiva no 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; }

Em várias linhas:

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
}

Exemplos:

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

Requer stat(1) , o que pode não estar presente em alguns sistemas.

Ele falhará se os nomes contiverem backticks, aspas simples ou "- >". Ele fica preso em um loop com loops symlink (isso pode ser resolvido usando um array associativo no Bash 4). Ele exporta uma variável chamada "cadeia" sem considerar se já está em uso.

Pode haver outros problemas com isso.

Editar:

Corrigido um problema com alguns links simbólicos relativos. Alguns ainda não funcionam, mas a versão abaixo não exige que o destino do link exista.

Adicionada uma versão que usa o 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
}
    
por 23.02.2010 / 18:34