Як перелічити символічні ланцюги посилань?


36

З огляду на цей приклад:

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

Якщо я виконую:

ls -l d

Він покаже:

d -> c

Чи існує спосіб для того, lsщоб показати чи іншу команду Linux d -> c -> b -> a?


Я перекреслював це як stackoverflow.com/questions/2320277/… Я сподіваюся, ви не заперечуєте.
Пол

Відповіді:


65

Просто використовуйте namei:

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

5
TIL. Це класна команда. upvotes
Том О'Коннор

Це має бути прийнятою відповіддю, оскільки вона показує повний ланцюжок посилань, як вимагається в оп. Далі з його допомогою можна перелічити весь каталог, схожий на ls. Спасибі!
фобічний

Дійсно, переглядав цю посаду, а namei - чудова команда!
Kalecser

використовувати команду "what", щоб знайти фактичне використання програми: $ namei `that java`
pdem

18

readlink -e <link>

readlink [ОПЦІЯ] ... ФАЙЛ

  • -e, --канонізувати існуючу
    канонізацію, дотримуючись кожне символьне посилання в кожному компоненті даної назви рекурсивно, всі компоненти повинні існувати
$ 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

Примітка: readlink a сам по собі повертає b

Примітка №2: разом з find -l утиліта для списку ланцюгів може бути легко записана в perl, але також повинна бути достатньо розумною для виявлення циклів

readlink нічого не виведе, якщо у вас є цикл. Це краще, ніж застрявати, я думаю.

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)

В ОС X: brew install coreutilsіgreadlink -e <link>
Хосе Альбан

3

Ось рекурсивна функція в 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; }

У кількох рядках:

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
}

Приклади:

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

Він вимагає того, stat(1)що може не бути в деяких системах.

Він не вийде, якщо імена містять зворотні посилання, одиничні лапки або "->". Він застрягає в циклі з петлями симпосилання (це можна вирішити за допомогою асоціативного масиву в Bash 4). Він експортує змінну, що називається "ланцюжок", без огляду на те, чи вона вже використовується.

З цим можуть виникнути й інші проблеми.

Редагувати:

Виправлена ​​проблема з деякими відносними посиланнями. Деякі досі не працюють, але версія нижче не вимагає існування цілі посилання.

Додана версія, що використовує 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
}

Я перевірив ваш сценарій, і він справді працює, але я віддаю перевагу щось простіше, тому я прийняв іншу відповідь, навіть якщо неповна.
Калексер

1
Гарний сценарій. Іноді мені хочеться побачити весь ланцюжок, і readlink, схоже , цього не показують. Java на Ubuntu є:/usr/bin/java -> /etc/alternatives/java -> /usr/lib/jvm/java-6-openjdk/jre/bin/java
Стефан Lasiewski

0

Ви можете просто обробити вихід namei чимось на кшталт awkабо grepотримати лише потрібні рядки:

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

або

namei d | egrep -e "->"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.