Linux: Найти все символические ссылки для данного «оригинального» файла?(обратная ссылка "readlink") - PullRequest
47 голосов
/ 26 декабря 2010

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

$ 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

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

Ура! * * 1013

Ответы [ 6 ]

131 голосов
/ 26 декабря 2010

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

find -L /dir/to/start -samefile /tmp/orig.file
30 голосов
/ 26 декабря 2010

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

Это похоже на «жесткие» ссылки, но впо крайней мере, они всегда находятся в одной и той же файловой системе, поэтому вы можете сделать 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 голосов
/ 26 декабря 2010

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

for i in *; do
    if [ -L "$i" ] && [ "$i" -ef /tmp/orig.file ]; then
        printf "Found: %s\n" "$i"
    fi
done
0 голосов
/ 14 апреля 2018

Вдохновленный комментарием Гордона Дэвиссона.Это похоже на другой ответ, но я получил желаемые результаты, используя exec.Мне нужно было что-то, что могло бы найти символические ссылки, не зная, где находится оригинальный файл.

find / -type l -exec ls -al {} \; | grep -i "all_or_part_of_original_name"
0 голосов
/ 21 декабря 2015

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

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

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

или

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

Я бы обычно использовал часть имени, например, '*orig*', чтобы начать, потому что мы знаем, что пользователи будут переименовывать (префикс) файл с простым именем с более описательным, например, «Январь, отчет из Лондона _ orig.file.2015.01. 21 "или что-то.

Примечание: я никогда не получал опцию -samefile для меня.

чисто, просто, легко запомнить

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

0 голосов
/ 26 декабря 2010

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