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.