Как изменить путь символической ссылки для многих файлов?

Мне было изменено имя каталога. В этом каталоге тысячи файлов. Некоторые проекты используют эти файлы, в проектах есть символические ссылки.

  1. Как найти все символические ссылки, которые имеют имя папки в своем адресе?
  2. как изменить все эти символические ссылки на другой путь в автоматическом режиме?

если 2 только скрипты bash с удалением и созданием нового - я сделаю это, но может быть вы знаете более простой способ?

1 ответ

Решение
  1. Это немного сложно, но это может быть сделано с find, readlinkпроверка, чтобы проверить, является ли символическая ссылка относительной или нет, и sed избавиться от .. в путевых именах (скопировано 1:1 из этого ответа).
    (Обратите внимание, что наиболее удобные методы (такие как readlink -f) недоступны из-за того, что цели символических ссылок больше не существуют.)
    Предполагая, что ваш старый путь /var/lib/old/path:

    oldpath='/var/lib/old/path';
    find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ...; fi;' \;
    
  2. Теперь замените ... сверху с ln -sf (-f переопределить существующую ссылку).
    Предполагая, что ваш новый путь /usr/local/my/awesome/new/path:

    oldpath='/var/lib/old/path';
    newpath='/usr/local/my/awesome/new/path';
    find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ln -sf "'"$newpath"'${p:'${#oldpath}'}" "{}"; fi;' \;
    

Обратите внимание, что oldpath а также newpath должны быть абсолютные пути.
Также обратите внимание, что это преобразует все относительные символические ссылки в абсолютные.
Можно было бы сохранить их относительными, но только с большими усилиями.

Ломать его

Для тех из вас, кому небезразлично, что на самом деле означает это однострочный:

  • find - классный исполняемый файл
  • / - где искать, в данном случае системный рут
  • -type l - сопоставить символические ссылки
  • -execdir - для каждого совпадения выполните следующую команду в каталоге соответствующего файла:
    • bash - хорошо, баш
    • -c - выполнить следующую строку (начальная и конечная ' удалены):
      • p="$(readlink "{}")"; - начиная с самого внутреннего:
        • " - начать строку, чтобы убедиться, что расширение не происходит
        • {} - заполнитель для имени совпадающего файла (особенность -execdir)
        • " - конец строки
        • readlink ... - узнать, куда указывает символическая ссылка
        • p="$(...)" - и сохранить результат в $p
      • if [ "${p:0:1}" != "/" ]; then - если первый символ $p является / (т.е. символическая ссылка является абсолютной), затем...
      • p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; - преобразовать путь в абсолютный:
        • $(pwd) - текущий каталог (где находится соответствующий файл, потому что мы используем -execdir)
        • /$p - добавить косую черту и цель символической ссылки к пути рабочего каталога
        • echo "$(pwd)/$p" | - передать вышеприведенное к следующей команде
        • sed ... - разрешить все ..смотри здесь
        • p="$(...)" и сохранить результат обратно в $p,
      • fi; - конец if
      • if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; - если $p начинается с $oldpath
        • ${p:0:'${#oldpath}'} - подстрока $pначиная с позиции 0с длиной $oldpath:
          • ${#oldpath} - длина переменной $oldpath
          • '...' - требуется, потому что мы внутри 'строка в кавычках
      • then - затем...
      • ln -sf - связать символически и переопределить существующий файл с аргументами:
        • "'"$newpath"'${p:'${#oldpath}'}" - заменить $oldpath часть $p с $newpath (фактически удалить столько символов из $p как $oldpath долго и готов $newpath к нему)
          • " - начать строку
          • ' - конец 'аргумент bash -c
          • " - добавить "-строка к нему (в которой происходит расширение переменной), содержащая:
          • $newpath - значение $newpath
          • " - конец "аргумент bash -c
          • ' - добавить '-строка к нему, содержащая:
          • ${p: - подстрока p, начинается с:
          • ' - закончить аргумент bash -c
          • ${#oldpath} - добавить длину $oldpath к этому
          • ' - добавить другой 'к ней
          • } - конец подстроки
          • " - конец строки
        • "{}" - файл ссылки, путь которого остается прежним
      • fi; - конец if
  • \; - разделитель для -execdir
Другие вопросы по тегам