¿Cómo editar recursivamente la ruta de los enlaces simbólicos?

Esta es una pregunta adicional que comenzó con esta: ¿Cómo editar enlaces simbólicos en OS X?

Ahora que sé cómo editar la ruta a la que apuntan los enlaces simbólicos, estoy tratando de averiguar cómo hacerlo recursivamente para cualquier enlace simbólico roto. Soy un tipo de PHP, por lo que esto de la CLI es algo extraño para mí...

Parece que hay algunos elementos específicos para esto, a saber:

  1. Identificar un enlace simbólico roto y recuperar su ubicación
  2. Obtener el destino anterior, ahora incorrecto, para el enlace simbólico
  3. Construya la nueva ruta correcta para que apunte el enlace simbólico
  4. Editar el enlace simbólico

El primero es bastante fácil:

find /path/to/search -type l | while read f; do if [ ! -e "$f" ]; then ls -l "$f"; fi; done

Esto me da una buena lista de todos los enlaces simbólicos rotos que se encuentran debajo del directorio proporcionado. Pero creo que necesitaría almacenar la ubicación de cada uno en una variable (¿matriz?) Para trabajar con ella.

A continuación, parece que cambiar la acción suministrada en la parte "entonces" de la lógica daría lugar a la solución.

El artículo 2 se puede recuperar usando:

readlink /path/to/broken/symlink

Así que parece que tenemos que meter eso en una variable. No tengo claro cómo hacer esto en la terminal.

El número 3 sería una simple edición de la ruta recuperada durante el paso 2. Necesito reemplazar el nombre de la unidad anterior por el nuevo. Entonces cambiando:

/Volumes/Old\ Drive/path/to/symlink

a

/Volumes/New\ Drive/path/to/symlink

Tampoco está claro exactamente cómo hacer esto dentro de un script CLI. Parece que se necesita algún tipo de reemplazo de cadena. Algo así como str_replace en el mundo de PHP.

Finalmente, el paso 4 se puede hacer a través de:

ln -f -s /path/to/new/location/of/original /path/to/location/of/broken/symlink/

como se detalla en mi otra pregunta, previamente vinculada anteriormente.

¿Cómo uniría exactamente estos conceptos para lograr el resultado deseado de arreglar todos mis enlaces simbólicos de una sola vez?

Respuestas (2)

Desde la parte superior de mi cabeza (y sin ninguna prueba):

  1. Cree un archivo de texto con el siguiente contenido

    #!/bin/bash
    
    find "$1" -type l | while read symlink; do
        if [ ! -e "$symlink" ]; then
            old_path=$(readlink "$symlink")
            new_path=${old_path/Old Drive/New Drive}
            ln -f -s "$new_path" "$symlink"
        fi
    done
    
  2. Hazlo ejecutable ejecutandochmod +x name-of-file

  3. Correr./name-of-file /path/to/search

Esto no se ha probado , así que pruébelo primero con un directorio de muestra.


Para agregar algunas explicaciones

  • old_path=$(readlink "$symlink")ejecuta el comando $(...)y asigna el resultado a$old_path
  • ${old_path/Old Drive/New Drive}hace sustitución de texto en$old_path
Gracias por esto, sin embargo, cuando intento ejecutar el script como se indica, simplemente obtengoRun: Command not found
Bueno, solo necesita escribir el resto de la línea (comenzando con el punto)
Aprendí algo bashde sintaxis nueva de este. ¡Así que un voto positivo por eso! ¡Gracias!
¡Oh! OK ahora se ejecutó. Sin embargo, no pareció hacer nada ... los enlaces simbólicos tienen una nueva marca de tiempo, pero aún están rotos como antes. Al tratar de entender su código, no tengo claro cómo está reemplazando la cadena en el nombre anterior para cambiarlo por el nuevo.
Está en la new_path=línea. Si agrega una muestra real de su ruta anterior y nueva, puedo ajustar el script en consecuencia.
Ohhhh, se supone que debo cambiar eso. Pensé que de alguna manera era dinámico LOL Me ajustaré y publicaré de nuevo si todavía tengo algún problema
Caliente diggity que funcionó perfectamente!! ¡Muchas gracias por el guión simple y elegante!

En un bashshell, para establecer una variable, simplemente use set NAME=bobo set VITAL_SIGNS=none.

También puede establecer una variable utilizando la salida de un comando llamando a la bashfunción incorporada readpara asignar la salida a una variable con nombre. Esto funciona bien en un flujo de tubería como este:

ls -l | wc -l | read NUMBER_OF_LINES

O puede asignar la salida directamente a una variable así:

LICENSE_KEY=$(cat ~/software/key.txt | grep KEY | awk '{print $1}')

Una excelente manera de leer variables recursivamente es en un bucle de la siguiente manera:

for BROKEN_LINK in $(commands to produce a list of files)
do
commands here to sort your links out, noting that the broken links are stored in the variable $BROKEN_LINKS
done

Con lo anterior en mente, algo como lo siguiente debería funcionar:

probar que una carpeta no existe

StuffeMac:dan stuffe$ ls ~/Desktop/broken_links
ls: /Users/stuffe/Desktop/broken_links: No such file or directory

probar que existe una nueva carpeta de destino

StuffeMac:dan stuffe$ ls ~/Desktop/working_links
StuffeMac:dan stuffe$

crear algunos enlaces no válidos y válidos

StuffeMac:dan stuffe$ ln -s ~/Desktop/brokenlinks/dan1
StuffeMac:dan stuffe$ ln -s ~/Desktop/brokenlinks/dan2
StuffeMac:dan stuffe$ ln -s ~/Desktop/working_links/dan3
StuffeMac:dan stuffe$ ln -s ~/Desktop/outofscopedeadlinks/dan4
StuffeMac:dan stuffe$ ls -l
total 32
lrwxr-xr-x  1 stuffe  staff  38  8 Dec 10:06 dan1 -> /Users/stuffe/Desktop/brokenlinks/dan1
lrwxr-xr-x  1 stuffe  staff  38  8 Dec 10:06 dan2 -> /Users/stuffe/Desktop/brokenlinks/dan2
lrwxr-xr-x  1 stuffe  staff  40  8 Dec 10:06 dan3 -> /Users/stuffe/Desktop/working_links/dan3
lrwxr-xr-x  1 stuffe  staff  46  8 Dec 10:21 dan4 -> /Users/stuffe/Desktop/outofscopedeadlinks/dan4

tome una lista de enlaces muertos en un archivo para la entrada

StuffeMac:dan stuffe$ find . -type l | while read f; do if [ ! -e "$f" ]; then ls "$f" >> deadlinks.txt; fi; done
StuffeMac:dan stuffe$ more deadlinks.txt
./dan1
./dan2
./dan4

ejecutar un bucle contra cada enlace muerto

StuffeMac:dan stuffe$ for DEAD_LINK in $(cat deadlinks.txt)
> do
> DESTINATION_IN_SCOPE=$(readlink $DEAD_LINK | grep brokenlinks | wc -l)
> NEW_DESTINATION="~/Desktop/working_links/"
> if [ $DESTINATION_IN_SCOPE = "1" ]
> then
> NEW_LINK=$(echo $DEAD_LINK | colrm 1 2)
> ln -f -s $NEW_DESTINATION$NEW_LINK $DEAD_LINK
> else
> echo "Link $DEAD_LINK not in target folder"
> fi
> done
Link ./dan4 not in target folder
StuffeMac:dan stuffe$

echa un vistazo a los enlaces simbólicos después de las ediciones

StuffeMac:dan stuffe$ ls -l
total 32
lrwxr-xr-x  1 stuffe  staff  28  8 Dec 10:08 dan1 -> ~/Desktop/working_links/dan1
lrwxr-xr-x  1 stuffe  staff  28  8 Dec 10:08 dan2 -> ~/Desktop/working_links/dan2
lrwxr-xr-x  1 stuffe  staff  40  8 Dec 10:06 dan3 -> /Users/stuffe/Desktop/working_links/dan3
lrwxr-xr-x  1 stuffe  staff  46  8 Dec 10:21 dan4 -> /Users/stuffe/Desktop/outofscopedeadlinks/dan4
La forma más moderna bashde obtener resultados de los comandos es usar la $(command)sintaxis like for MYVAR in $(ls | grep somefilter)en lugar de usar acentos graves. Tiene algunas ventajas sobre los acentos graves como este . Hice ediciones basadas en esto.
Tampoco es un git analizar correctamente en SE markdown;)