Perbarui Batch Tautan Simbolik Secara Rekursif

12

Saya memiliki aplikasi web yang memiliki banyak tautan simbolik di dalam subdirektori di dalamnya. Saya perlu memindahkan aplikasi ke struktur direktori lain, dan saya perlu memperbarui semua symlink untuk menunjuk ke jalur baru. Sebagai contoh:

Dir Lama: Dir /home/user/public_html/dev
Baru: /home/user/public_html/qa
Symlink Lama: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
Symlink Baru:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

Masalahnya adalah bahwa ada banyak ini tersebar di berbagai direktori. Bagaimana saya bisa secara rekursif mencari dari akar dan menciptakan semua symlink menunjuk ke /dev/dengan /qa/?

ggutenberg
sumber

Jawaban:

16

Perintah bash ini harus melakukannya untuk Anda:

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

Ini digunakan finduntuk mengidentifikasi semua file dalam qadirektori yang merupakan tautan simbolik dengan target yang ada di devdirektori, dan untuk masing-masingnya, ia mencetak perintah bash yang akan mengganti tautan dengan tautan ke jalur yang setara di qa/. Setelah Anda menjalankan ini, jalankan saja skrip yang dibuat dengan

bash script.sh

Anda mungkin ingin memeriksanya secara manual terlebih dahulu untuk memastikan itu berhasil.

Berikut ini adalah versi verbose dari findperintah di atas untuk membaca lebih mudah (meskipun saya tidak harus menulis seperti ini dalam praktiknya):

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
sumber
Ini menciptakan script.sh kosong. Dan menjalankan perintah find: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' tidak menghasilkan apa-apa.
ggutenberg
Anda memang ingat untuk mengubah jalur ke yang sebenarnya di sistem file Anda, kan? Apa yang terjadi jika Anda berlari saja find /home/usr/public_html/qa/ -type l? Jika itu tidak menemukan tautan, sesuatu yang sangat aneh terjadi pada sistem Anda.
David Z
Ya, " find /home/user/public_html/qa/ -type l" menghasilkan tautan. Tetapi menambahkan -lname parameter itu tidak menghasilkan apa-apa.
ggutenberg
Sebenarnya, pada pengujian lebih lanjut sepertinya ini berfungsi. Tidak yakin apa yang saya lakukan salah kemarin, tapi sepertinya baik-baik saja sekarang. Terima kasih.
ggutenberg
Hah, aneh. Nah, jika Anda pernah mencari tahu apa yang salah, beri komentar di sini. Saya penasaran.
David Z
5

Jika ada orang lain yang menemukan ini ketika mencari solusi: Buat file bernama "linkmod.sh" yang mengandung:

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

dan lari

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

Anda dapat menggunakan opsi -l dalam menemukan jika diperlukan.

CATATAN: Anda harus menggunakan 2x \ dalam pola sebelum karakter apa pun yang memerlukan \ sed, karena gema menghapus satu. Sebagai contoh

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

Hapus echodari baris terakhir jika perintah ln benar.

rknC
sumber
Mungkin baik untuk memperjelas bahwa baik echodi garis akhir dari naskah dan echodi find .. | xargs .. linkmod.sh ...perintah itu sendiri baik perlu dihapus.
Kyle Strand
2

Saya membuat skrip bash link_rename.shuntuk mengubah nama tautan simbolik secara rekursif dalam direktori yang diberikan

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

Ini dapat dieksekusi sebagai link_rename.sh /home/human/dir link1 link2

Script memiliki 3 argumen:

  1. Direktori tempat Anda ingin melakukan perubahan nama batch symlink
  2. Pola lama. Inilah link1pola lama yang akan diganti
  3. Pola baru. Berikut link2adalah pola baru yang link1akan diganti

Script secara rekursif membaca semua symlink di direktori menggunakan find "$DIR" -type l dan memprosesnya baris demi baris.

$line adalah symlink yang perlu diganti namanya

CUR_LINK_PATH adalah jalan lama

NEW_LINK_PATH diperoleh dengan melakukan penggantian string di jalur tautan lama.

Symlink lama dihapus dan symlink baru dibuat menggunakan ln -s "$NEW_LINK_PATH" "$line"

Akhil Mohan
sumber
0

Saya akhirnya menulis skrip PHP command-line yang tampaknya melakukan trik.

<?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
sumber