Linux: найти все символические ссылки для данного "оригинального" файла? (обратная 'readlink')

Рассмотрим следующий фрагмент командной строки:

$ cd /tmp/
$ mkdir dirA
$ mkdir dirB
$ echo "the contents of the 'original' file" > orig.file
$ ls -la orig.file 
-rw-r--r-- 1 $USER $USER 36 2010-12-26 00:57 orig.file

# create symlinks in dirA and dirB that point to /tmp/orig.file:

$ ln -s $(pwd)/orig.file $(pwd)/dirA/
$ ln -s $(pwd)/orig.file $(pwd)/dirB/lorig.file
$ ls -la dirA/ dirB/
dirA/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:57 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:57 orig.file -> /tmp/orig.file

dirB/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:58 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:58 lorig.file -> /tmp/orig.file

В этот момент я могу использовать readlink, чтобы увидеть, что такое "оригинал" (ну, я полагаю, что обычный термин здесь либо "цель", либо "источник", но те, которые у меня в голове, могут быть противоположными понятиями: ну, так я просто назову его "оригинальным" ) файлом символических ссылок, т.е.

$ readlink -f dirA/orig.file 
/tmp/orig.file
$ readlink -f dirB/lorig.file 
/tmp/orig.file

... Однако я хотел бы знать, есть ли команда, которую я мог бы запустить в "исходном" файле, и найти все символические ссылки, которые указывают на нее? Другими словами, что-то вроде (псевдо):

$ getsymlinks /tmp/orig.file
/tmp/dirA/orig.file 
/tmp/dirB/lorig.file

Заранее благодарим за любые комментарии,

Ура!

Ответ 1

Я не видел команды для этого, и это не простая задача, так как целевой файл содержит нулевую информацию о том, какие исходные файлы указывают на нее.

Это похоже на "жесткие" ссылки, но по крайней мере они всегда находятся в одной файловой системе, поэтому вы можете сделать find -inode, чтобы перечислить их. Мягкие ссылки более проблематичны, так как они могут пересекать файловые системы.

Я думаю, что вам нужно сделать в основном выполнить ls -al для каждого файла всей иерархии и использовать grep для поиска -> /path/to/target/file.

Например, вот один из них, который я запускал в своей системе (отформатирован для удобочитаемости - последние две строки на самом деле находятся на одной строке в реальном выходе):

pax$ find / -exec ls -ald {} ';' 2>/dev/null | grep '\-> /usr/share/applications'
lrwxrwxrwx 1 pax pax 23 2010-06-12 14:56 /home/pax/applications_usr_share
                                         -> /usr/share/applications

Ответ 2

Используя GNU find, это найдет файлы, которые связаны или связаны с файлом:

find -L /dir/to/start -samefile /tmp/orig.file

Ответ 3

Символы не отслеживают то, что указывает на данный пункт назначения, поэтому вы не можете сделать лучше, чем проверять каждую символическую ссылку, чтобы увидеть, указывает ли она на нужный пункт назначения, например

for i in *; do
    if [ -L "$i" ] && [ "$i" -ef /tmp/orig.file ]; then
        printf "Found: %s\n" "$i"
    fi
done

Ответ 4

Вот что я придумал. Я делаю это на OS X, у которого нет readlink -f, поэтому мне пришлось использовать вспомогательную функцию для ее замены. Если у вас есть правильный readlink -f, вы можете использовать это вместо этого. Кроме того, использование while ... done < <(find ...) строго не требуется в этом случае, простое find ... | while ... done будет работать; но если вы когда-либо захотели сделать что-то вроде установки переменной внутри цикла (например, количество совпадающих файлов), версия pipe завершится неудачно, потому что цикл while будет выполняться в подоболочке. Наконец, обратите внимание, что я использую find ... -type l, поэтому цикл выполняется только на символических ссылках, а не на других типах файлов.

# Helper function 'cause my system doesn't have readlink -f
readlink-f() {
    orig_dir="$(pwd)"
    f="$1"
    while [[ -L "$f" ]]; do
        cd "$(dirname "$f")"
        f="$(readlink "$(basename "$f")")"
    done
    cd "$(dirname "$f")"
    printf "%s\n" "$(pwd)/$(basename "$f")"
    cd "$orig_dir"
}

target_file="$(readlink-f "$target_file")" # make sure target is normalized

while IFS= read -d '' linkfile; do
    if [[ "$(readlink-f "$linkfile")" == "$target_file" ]]; then 
        printf "%s\n" "$linkfile"
    fi
done < <(find "$search_dir" -type l -print0)

Ответ 5

Это может быть слишком упрощенным для того, что вы хотите сделать, но я считаю это полезным. он не отвечает на ваш вопрос буквально, так как он не "работает на исходном файле", но выполняет задачу. Но гораздо больше доступа к жесткому диску. И он работает только для "мягких" связанных файлов, которые составляют большинство связанных с пользователем файлов.

из корня вашего каталога хранения данных или каталогов данных пользователей, где бы symlinked 'файлы' в orig.file не могли проживать, запустите команду find:

# find -type l -ls |grep -i 'orig.file' 

или

# find /Starting/Search\ Path/ -type l -ls |grep -i '*orig*'

Я бы обычно использовал часть имени, например, '*orig*', чтобы начать, потому что мы знаем, что пользователи переименуют (префикс) просто именованный файл с более описательным, например "Jan report from London _ orig.file.2015.01. 21" или что-то еще.

Примечание. Я никогда не использовал параметр -samefile для меня.

чистый, простой, легко запоминающийся

надеюсь, что это поможет кому-то. Landis.