Actualización por lotes de enlaces simbólicos recursivamente


12

Tengo una aplicación web que tiene un montón de enlaces simbólicos en subdirectorios. Necesito mover la aplicación a otra estructura de directorio, y necesito actualizar todos los enlaces simbólicos para que apunten a la nueva ruta. Por ejemplo:

Edad Dir: /home/user/public_html/dev
Nueva Dir: /home/user/public_html/qa
Antiguo enlace simbólico: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
Nuevo enlace simbólico:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

El problema es que hay muchos de estos dispersos en varios directorios. ¿Cómo puedo buscar recursivamente desde la raíz y recrear todos los enlaces simbólicos que apuntan /dev/con /qa/?

Respuestas:


16

Este comando bash debería hacerlo por ti:

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

Se utiliza findpara identificar todos los archivos en el qadirectorio que son enlaces simbólicos con un objetivo que está en el devdirectorio, y para cada uno, imprime un comando bash que reemplazará el enlace con un enlace a la ruta equivalente qa/. Después de ejecutar esto, simplemente ejecute el script generado con

bash script.sh

Es posible que desee examinarlo manualmente primero para asegurarse de que funcionó.

Aquí hay una versión más detallada del findcomando anterior para una lectura más fácil (aunque no necesariamente lo escribiría de esta manera en la práctica):

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

Esto crea un script.sh vacío. Y ejecutando el comando find como tal: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' no genera nada.
ggutenberg

Recordaste cambiar las rutas a las reales en tu sistema de archivos, ¿verdad? ¿Qué pasa si corres solo find /home/usr/public_html/qa/ -type l? Si eso no encuentra los enlaces, algo muy extraño está sucediendo con su sistema.
David Z

Sí, " find /home/user/public_html/qa/ -type l" genera los enlaces. Pero agregar el parámetro -lname no genera nada.
ggutenberg

En realidad, en pruebas posteriores parece que esto está funcionando. No estoy seguro de lo que estaba haciendo mal ayer, pero parece estar bien ahora. Gracias.
ggutenberg

Huh, raro Bueno, si alguna vez descubres lo que estaba mal, pon un comentario aquí. Soy curioso.
David Z

5

En caso de que alguien más encuentre esto cuando busque una solución: Cree un archivo llamado "linkmod.sh" que contenga:

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

y correr

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

Puede usar la opción -lname en find si es necesario.

NOTA: debe usar 2x \ en los patrones antes de cualquier carácter que requiera \ in sed, ya que echo elimina uno. Por ejemplo

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

Elimine el echode la última línea si los comandos ln son correctos.


Puede ser bueno para aclarar que tanto el echoen la línea final de la secuencia de comandos y el echoen el find .. | xargs .. linkmod.sh ...propio comando tanto necesitan ser removidos.
Kyle Strand

2

Creé un script bash link_rename.shpara el cambio recursivo de enlaces simbólicos en un directorio dado

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

Se puede ejecutar como link_rename.sh /home/human/dir link1 link2

El script tiene 3 argumentos:

  1. El directorio en el que desea realizar el cambio de nombre por lotes de enlaces simbólicos
  2. El viejo patrón. Aquí link1está el viejo patrón que será reemplazado
  3. El nuevo patrón. Aquí link2está el nuevo patrón con el que link1será reemplazado

El script lee recursivamente todos los enlaces simbólicos en el directorio usando find "$DIR" -type l y los procesa línea por línea.

$line es el enlace simbólico que necesita ser renombrado

CUR_LINK_PATH es el viejo camino

NEW_LINK_PATH se obtiene mediante la sustitución de la cadena en la ruta de enlace anterior.

El antiguo enlace simbólico se elimina y se crea un nuevo enlace simbólico usando ln -s "$NEW_LINK_PATH" "$line"


0

Terminé escribiendo un script PHP de línea de comandos que parece hacer el truco.

<?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";
            }
        }
    }
}
?>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.