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


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



Ура!

748   6  

6 ответов:

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

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

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

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

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

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

Вот что я придумал. Я делаю это на 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)

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

find / -type l -exec ls -al {} \; | grep -i "all_or_part_of_original_name"

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

Из корневого каталога хранения данных или каталогов данных пользователей, где бы ни находились 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.файл.2015.01.21 " или что-то в этом роде.

Примечание: Я никогда не получал опцию-samefile, чтобы работать на меня.

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

Надеюсь, что это помогает кто-то. Лэндис.

Comments

    Ничего не найдено.