Как я могу «связать» много сломанных символических ссылок?

54

У меня есть дерево каталогов, в котором есть куча символических ссылок на файлы в /home... однако я перешел /homeна /mnt/homeи мне нужен способ "связать" все символические ссылки . Существует ли такая функциональность или мне нужно написать скрипт для этого?

В качестве примера у меня есть что-то вроде следующего:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

Я хочу команду, которая будет находить все символические ссылки и ссылаться на те же места, но под /mnt/homeвместо/home

Существует ли такая команда?

мистифицировать
источник

Ответы:

55

Нет команды для перенацеливания символической ссылки, все, что вы можете сделать, это удалить ее и создать другую. Предполагая, что у вас есть утилиты GNU (например, под не встроенным Linux или Cygwin), вы можете использовать -lnameпервичное из findдля сопоставления символических ссылок по их цели и readlinkдля чтения содержимого ссылки. Непроверенные:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "/mnt$(readlink "$0")" "$0"' {} \;

Было бы лучше сделать эти символические ссылки относительными. Есть удобная небольшая утилита под названием symlinks(первоначально Mark Lords, теперь поддерживаемая J. Brandt Buckley), присутствующая во многих дистрибутивах Linux. Перед перемещением или после восстановления действительных ссылок, как описано выше, запустите, symlinks -c /mnt/home/someone/somethingчтобы преобразовать все абсолютные символические ссылки в указанном каталоге в относительные символические ссылки, если они не пересекают границу файловой системы.

Жиль "ТАК - перестань быть злым"
источник
Без обид, это отличная однострочная строка, но подстановка строк в Bash, вероятно, могла бы творить чудеса с изменением пути и была бы проще.
0xC0000022L
@STATUS_ACCESS_DENIED Как так? Единственная строковая операция заключается /mntв добавлении к пути; вам не нужна более сложная строковая операция, чем конкатенация.
Жиль "ТАК - перестань быть злым"
@ Жиль: извините, я больше думал о вашем замечании с относительными путями. Для точного «перевода» вашего примера вы, конечно, правы.
0xC0000022L
13

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

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

например. После изменения имени пользователя заменить старое имя пользователя новым именем пользователя в качестве цели для многих ссылок после того, как перемещение уже было сделано. Создайте скрипт под названием replace-simlinks, показанный ниже:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo shows the correct commands are being issued, then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

и вызовите его с помощью следующей команды:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

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

edit: Спасибо Gilles за кикстарт этого скрипта и подсказку об использовании скрипта символических ссылок, чтобы сделать ссылки относительными.

Gerry
источник
1
Я считаю, что это решение лучше, потому что оно использует замену строки, которая помогает в тех случаях, когда вам нужно изменить имя папки в середине пути. Решение также довольно легко изменить, чтобы выполнить более сложные преобразования, если это необходимо.
Gallaecio
Я бы рекомендовал заключать аргументы в строковую подстановку, поскольку это должно быть сделано для использования косых черт, например, для пути в вопросе OP. target=${target/"/home"/"/mnt/home"}Очень полезно, хотя. Благодарю.
Вальтер Ниссен
3

Создайте /homeкак символическую ссылку /mnt/home, и все существующие символические ссылки снова будут действительны.

Кит Томпсон
источник
2
Монтирование привязок