Пакетное обновление символических ссылок рекурсивно

12

У меня есть веб-приложение, в котором есть несколько символических ссылок в подкаталогах. Мне нужно переместить приложение в другую структуру каталогов, и мне нужно обновить все символические ссылки, чтобы указать новый путь. Например:

Старый Dir: /home/user/public_html/dev
New Dir: /home/user/public_html/qa
Старый Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
Новый Symlink:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

Проблема в том, что их много в разных каталогах. Как я могу рекурсивно искать из корня и воссоздать все символические ссылки, указывающие на /dev/с /qa/?

ggutenberg
источник

Ответы:

16

Эта команда bash должна сделать это за вас:

find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' -printf 'ln -nsf "$(readlink "%p" | sed s/dev/qa/)" "$(echo "%p" | sed s/dev/qa/)"\n' > script.sh

Он использует findдля идентификации всех файлов в qaкаталоге, которые являются символическими ссылками, с целью, находящейся в devкаталоге, и для каждого из них он выводит команду bash, которая заменит ссылку ссылкой на эквивалентный путь в qa/. После этого просто запустите сгенерированный скрипт с

bash script.sh

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

Вот более подробная версия приведенной выше findкоманды для более удобного чтения (хотя на практике я не обязательно писал бы ее так):

SRC_DIR="/home/user/public_html/qa"
OLD_TARGET="/home/user/public_html/dev"
SUB="s/dev/qa/"

find $SRC_DIR -type l \
  -lname "$OLD_TARGET/*" -printf \
  'ln -nsf "$(readlink "%p"|sed $SUB)" "$(echo "%p"|sed $SUB)"\n'\
 > script.sh
Дэвид З
источник
Это создает пустой скрипт .sh. И запуск команды find так: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' ничего не выводится.
Ггутенберг
Вы не забыли изменить пути к фактическим в вашей файловой системе, верно? Что произойдет, если вы просто бежите find /home/usr/public_html/qa/ -type l? Если ссылки не найдены, с вашей системой происходит что-то очень странное.
Дэвид З
Да, " find /home/user/public_html/qa/ -type l" выводит ссылки. Но добавление параметра -lname ничего не выводит.
Ггутенберг
На самом деле, при дальнейшем тестировании похоже, что это работает. Не уверен, что я делал не так вчера, но сейчас все в порядке. Спасибо.
Ггутенберг
Да странно. Ну, если вы когда-нибудь выясните, что происходит не так, оставьте комментарий здесь. Мне любопытно.
Дэвид З
5

Если кто-то еще находит это при поиске решения: создайте файл с именем «linkmod.sh», содержащий:

#!/bin/sh
PATTERN1=`echo "$2"`
PATTERN2=`echo "$3"`
LINKNAME=`echo "$1"`
OLDTARGET=`readlink "$1"`
NEWTARGET=`echo "$OLDTARGET" \
| sed -e 's/'"$PATTERN1"'/'"$PATTERN2"'/'`
echo ln -nsf "$NEWTARGET" "$LINKNAME"

и беги

find . -type l -print0 | xargs -0IX echo linkmod.sh X "pattern1" "pattern2"

При необходимости вы можете использовать опцию -lname в find.

ПРИМЕЧАНИЕ: вы должны использовать 2x \ в шаблонах перед любыми символами, которые требуют \ in sed, так как echo удаляет один. Например

find . -type l -print0 | xargs -0IX echo linkmod.sh X "folder\\ name\\/file" "folder2\\ name\\/file"

Удалите echoиз последней строки, если команды ln верны.

rknC
источник
Может быть хорошо , чтобы уточнить , что и echoв последней строке этого сценария и echoв find .. | xargs .. linkmod.sh ...самой команде и должны быть удалены.
Кайл Стрэнд,
2

Я создал скрипт bash link_rename.shдля рекурсивного переименования символических ссылок в данном каталоге

#! /bin/bash

DIR=$1
OLD_PATTERN=$2
NEW_PATTERN=$3

while read -r line
do
    echo $line
    CUR_LINK_PATH="$(readlink "$line")"
    NEW_LINK_PATH="$CUR_LINK_PATH"  
    NEW_LINK_PATH="${NEW_LINK_PATH/"$OLD_PATTERN"/"$NEW_PATTERN"}"
    rm "$line"
    ln -s "$NEW_LINK_PATH" "$line"
done <<< $(find "$DIR" -type l)

Это может быть выполнено как link_rename.sh /home/human/dir link1 link2

Скрипт имеет 3 аргумента:

  1. Каталог, в котором вы хотите выполнить пакетное переименование символических ссылок
  2. Старый шаблон. Вот link1старый шаблон, который будет заменен
  3. Новый шаблон. Вот link2новая модель с которой link1будет заменена

Сценарий рекурсивно читает все символические ссылки в каталоге, используя find "$DIR" -type l и обрабатывает их построчно.

$line символическая ссылка, которую нужно переименовать

CUR_LINK_PATH старый путь

NEW_LINK_PATH получается путем замены строки в старом пути ссылки.

Старая символическая ссылка удаляется, а новая символическая ссылка создается с помощью ln -s "$NEW_LINK_PATH" "$line"

Ахил Мохан
источник
0

Я закончил тем, что написал сценарий PHP командной строки, который, кажется, делает свое дело.

<?php
//Run via command-line
$dir = new RecursiveDirectoryIterator('.');
foreach(new RecursiveIteratorIterator($dir) as $file) {
    //$link = readlink($file);
    if(is_link($file)) {
        $old_link = readlink($file);
        $new_link = str_ireplace("/joomla/", "/qa/", $old_link);
        if($new_link != $old_link) {
            exec('rm "'.$file.'"');
            exec('ln -fs "'.$new_link.'" "'.$file.'"');
            $new_link = readlink($file);
            if($new_link == $old_link) {
                echo $file."\t".$old_link."\t".$new_link."\n";
            }
        }
    }
}
?>
ggutenberg
источник