Batch Update Symboliczne linki Rekurencyjnie

13

Mam aplikację internetową, która zawiera wiele dowiązań symbolicznych w podkatalogach. Muszę przenieść aplikację do innej struktury katalogów i muszę zaktualizować wszystkie dowiązania symboliczne, aby wskazywały nową ścieżkę. Na przykład:

Stary katalog: /home/user/public_html/dev
Nowy katalog: /home/user/public_html/qa
Stary symbol: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
Nowy symbol:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

Problem polega na tym, że jest ich wiele w różnych katalogach. Jak mogę rekurencyjnie wyszukiwać od katalogu głównego i ponownie tworzyć wszystkie dowiązania symboliczne wskazujące za /dev/pomocą /qa/?

Ggutenberg
źródło

Odpowiedzi:

17

To polecenie bash powinno to zrobić za Ciebie:

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

Służy finddo identyfikowania wszystkich plików w qakatalogu, które są dowiązaniami symbolicznymi, z celem znajdującym się w devkatalogu, i dla każdego z nich wypisuje polecenie bash, które zastąpi łącze linkiem do równoważnej ścieżki w qa/. Po uruchomieniu uruchom skrypt za pomocą

bash script.sh

Możesz najpierw sprawdzić to ręcznie, aby upewnić się, że zadziałało.

Oto bardziej szczegółowa wersja powyższego findpolecenia dla łatwiejszego czytania (choć niekoniecznie napisałabym to w praktyce):

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
David Z
źródło
To tworzy pusty skrypt.sh. Uruchomienie polecenia find w ten sposób: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' nic nie wyświetla.
ggutenberg
Pamiętasz, jak zmienić ścieżki do rzeczywistych w systemie plików, prawda? Co się stanie, jeśli po prostu uciekniesz find /home/usr/public_html/qa/ -type l? Jeśli to nie znajdzie linków, w twoim systemie dzieje się coś bardzo dziwnego.
David Z
Tak, ” find /home/user/public_html/qa/ -type l” wyświetla linki. Ale dodanie parametru -lname niczego nie wyświetla.
ggutenberg
Właściwie po dalszych testach wygląda na to, że to działa. Nie jestem pewien, co robiłem wczoraj źle, ale wydaje się teraz w porządku. Dzięki.
ggutenberg
Hej, dziwne. Cóż, jeśli kiedykolwiek zorientujesz się, co poszło nie tak, napisz tutaj komentarz. Jestem ciekawy.
David Z
5

Jeśli ktoś inny znajdzie to podczas szukania rozwiązania: Utwórz plik o nazwie „linkmod.sh” zawierający:

#!/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"

i biegnij

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

W razie potrzeby możesz użyć opcji -lname w find.

UWAGA: musisz użyć 2x \ we wzorach przed dowolnymi znakami, które wymagają \ w sed, ponieważ echo usuwa jeden. Na przykład

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

Usuń echoostatni wiersz, jeśli polecenia ln są poprawne.

rknC
źródło
Może być dobre wyjaśnienie, że zarówno echow ostatnim wierszu skryptu oraz echow find .. | xargs .. linkmod.sh ...poleceniu samego obie muszą zostać usunięte.
Kyle Strand,
2

Stworzyłem skrypt bash link_rename.shdla rekurencyjnej zmiany nazw dowiązań symbolicznych w danym katalogu

#! /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)

Można go wykonać jako link_rename.sh /home/human/dir link1 link2

Skrypt ma 3 argumenty:

  1. Katalog, w którym chcesz wykonać wsadową zmianę nazwy dowiązań symbolicznych
  2. Stary wzór. Oto link1stary wzór, który zostanie zastąpiony
  3. Nowy wzór. Oto link2nowy wzór, który link1zostanie zastąpiony

Skrypt rekurencyjnie odczytuje wszystkie dowiązania symboliczne w katalogu przy użyciu find "$DIR" -type l i przetwarza je wiersz po wierszu.

$line jest dowiązaniem symbolicznym, którego nazwę należy zmienić

CUR_LINK_PATH to stara ścieżka

NEW_LINK_PATH jest uzyskiwany przez wykonanie zamiany łańcucha na starej ścieżce łącza.

Stare symlink jest usuwane i nowe symlink jest tworzone przy użyciu ln -s "$NEW_LINK_PATH" "$line"

Akhil Mohan
źródło
0

Skończyło się na napisaniu skryptu PHP w wierszu poleceń, który wydaje się załatwić sprawę.

<?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
źródło