Como listar cadeias de links simbólicas?

36

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 lsou qualquer outro comando linux para mostrar d -> c -> b -> a?

Kalecser
fonte
Cruzei isso como stackoverflow.com/questions/2320277/… Espero que você não se importe.
Paul

Respostas:

65

Basta usar namei:

$ namei d
f: d
 l d -> c
   l c -> b
     l b -> a
       d a
Mike
fonte
5
TIL. Este é um comando legal . # 1
Tom O'Connor
Essa deve ser a resposta aceita, pois mostra a cadeia completa de links, conforme solicitado no op. Além disso, pode ser usado para listar um diretório inteiro semelhante a ls. Obrigado!
Phobic #:
Na verdade, estava revisitando este post e namei é um comando maravilhoso!
Kalecser 30/03
use com o comando "what" para encontrar o uso real de um programa: $ namei `what java`
pdem 4/04/2017
18

readlink -e <link>

readlink [OPÇÃO] ... ARQUIVO

  • -e, --canonicalize-
    canonicalize existente seguindo cada link simbólico em cada componente do nome fornecido recursivamente, todos os componentes devem existir
$ 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: o readlink a retorna por si só b

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

O readlink não produzirá nada se você tiver um loop. É 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)
Paulo
fonte
No OS X: brew install coreutilsegreadlink -e <link>
Jose Alban
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 o stat(1)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 de link simbólico (isso pode ser resolvido usando uma matriz associativa no Bash 4). Ele exporta uma variável chamada "cadeia" sem considerar se ela 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
}
Pausado até novo aviso.
fonte
Testei seu script e ele realmente funciona, mas prefiro algo mais simples, por isso aceitei a outra resposta, mesmo que incompleta.
Kalecser
1
Bom roteiro. Às vezes, quero ver toda a cadeia e readlinknão parece mostrar isso. O Java no Ubuntu é:/usr/bin/java -> /etc/alternatives/java -> /usr/lib/jvm/java-6-openjdk/jre/bin/java
Stefan Lasiewski
0

Você pode apenas pós-processar a saída do namei com algo como awkou greppara obter apenas as linhas que deseja:

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

ou

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