Пакетне оновлення символічних посилань рекурсивно


13

У мене є веб-додаток, який містить безліч символічних посилань у підкаталогах. Мені потрібно перемістити додаток до іншої структури каталогу, і мені потрібно оновити всі посилання, щоб вказати на новий шлях. Наприклад:

Old Dir: /home/user/public_html/dev
New Dir: /home/user/public_html/qa
Old Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
New Symlink:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

Проблема полягає в тому, що їх багато розкидано по різних каталогах. Як я можу рекурсивно шукати від кореня і відтворити все символічні посилання , що вказують /dev/з /qa/?

Відповіді:


17

Ця команда 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

Це створює порожній script.sh. І запустивши команду find так: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' нічого не виводить.
ggutenberg

Ви пам'ятали, щоб змінити шляхи до фактичних у вашій файловій системі, правда? Що станеться, якщо ти просто біжиш find /home/usr/public_html/qa/ -type l? Якщо це не знайде посилань, з вашою системою відбувається щось дуже дивне.
David Z

Так, " find /home/user/public_html/qa/ -type l" виводить посилання. Але додаючи параметр -lname, він нічого не виводить.
ggutenberg

Насправді, при подальшому тестуванні, схоже, це працює. Не впевнений, що я робив неправильно вчора, але здається нормальним зараз. Дякую.
ggutenberg

Так, дивно. Ну, якщо ви коли-небудь зрозумієте, що пішло не так, поставте тут коментар. Мені цікаво.
David Z

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, якщо знадобиться.

ПРИМІТКА. Ви повинні використовувати 2x \ у шаблонах перед будь-якими символами, які потребують \ in sed, оскільки ехо видаляє один. Наприклад

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

Видаліть echoз останнього рядка, якщо команди ln є правильними.


Можливо, добре уточнити, що і 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";
            }
        }
    }
}
?>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.