Tengo un montón de enlaces simbólicos a otra unidad. Necesito mover todos los archivos de esa unidad a los que se hace referencia en otro lugar para poder eliminarlos.
Marty Trenouth
Respuestas:
14
Para algunas definiciones de "fácil":
#!/bin/shset-efor link;do
test -h "$link"||continue
dir=$(dirname "$link")
reltarget=$(readlink "$link")case $reltarget in/*) abstarget=$reltarget;;*) abstarget=$dir/$reltarget;;esac
rm -fv "$link"
cp -afv "$abstarget""$link"||{# on failure, restore the symlink
rm -rfv "$link"
ln -sfv "$reltarget""$link"}done
Ejecute este script con nombres de enlaces como argumentos, por ejemplo, a través de find . -type l -exec /path/tos/script {} +
Gracias por la edición, anon, pero el guión hace nombres de archivo de la manija con espacios muy bien, citando las variables en todos los lugares necesarios. Cambiar "$var"a "${var}"es un noop en sh / bash. Eliminé el bashism ( [[), el resto es compatible con POSIX sh.
Grawity
Un método aún más robusto para manejar fallas de enlaces simbólicos es cpun archivo temporal en el mismo directorio y luego mv -fese archivo temporal en el original. Esto debería evitar problemas como personas que se mantienen presionadas Ctrl-Co que el sistema de archivos se llene entre los comandos rmy cp(evitando así que incluso los nuevos lnfuncionen). Los nombres de archivo temporales son fáciles de detectar ls -apara una limpieza posterior si es necesario.
Sr. Fooz
Como nota al margen, en serio no puedo recordar por qué no solo utilicé en abstarget=$(readlink -f "$link")lugar del bloque de casos , sino que podría haber sido por razones de portabilidad.
Grawity
17
Puede ser más fácil usar tar para copiar los datos a un nuevo directorio.
-H (c and r mode only)Symbolic links named on the command line will
be followed; the target of the link will be archived, not the
link itself.
Podrías usar algo como esto
tar -hcf - sourcedir | tar -xf --C newdir
tar --help:-H,--format=FORMAT create archive of the given format
-h,--dereference follow symlinks; archive and dump the files they point to
Gracias, casi lo que necesitaba: tenía que hacer algo como: cp -L files tmp/ && rm files && cp tmp/files . si aclaras, probablemente ayudarás a más personas ...
sabio
5
"fácil" será una función tuya, muy probablemente.
Probablemente escribiría un script que usa la utilidad de línea de comando "find" para encontrar archivos vinculados simbólicamente, luego llama a rm y cp para eliminar y reemplazar el archivo. Probablemente harías bien en hacer que la acción llamada por find compruebe que queda suficiente espacio libre antes de mover también el enlace sym.
Otra solución puede ser montar el sistema de archivos en cuestión a través de algo que oculta los enlaces simbólicos (como samba), luego simplemente copie todo. Pero en muchos casos, algo así introduciría otros problemas.
Una respuesta más directa a su pregunta es probablemente "sí".
Editar: según la solicitud de información más específica. De acuerdo con la página de manual de find , este comando enumerará todos los archivos de enlace sym en una profundidad de 2 directorios, desde /:
Para obtener find para ejecutar algo al encontrarlo:
find /-maxdepth 2-type l -exec ./ReplaceSymLink.sh {} \;
Creo que llamará a un script que acabo de inventar y pasará el nombre de archivo que acaba de encontrar. Alternativamente, puede capturar la salida de búsqueda al archivo (use "find [blah]> symlinks.data", etc.) y luego pasar ese archivo a un script que haya escrito para manejar la copia sobre el original con gracia.
¡Esto es para buscar los elementos y el que está marcado como respuesta se usa para reemplazar los enlaces!
Marty Trenouth
3
Este es el oneliner que he usado: suponga que todos los archivos locales son enlaces a otro archivo en "fuente". Puede refinar la selección de archivos con patrones o "buscar". Por favor, comprenda antes de usar.
para f en *; do cp --remove-destination source / $ f $ f; hecho
¿qué tal usar readlink: para f en *; do cp ---- remove-destination "$ (readlink $ f)" "$ f"; hecho
Diego
Sí, es una buena idea, pero pierde el control de la operación. Un límite de mi solución es que no funciona para archivos con espacios en blanco en el medio, o para listas muy largas. Probablemente la solución final es juntar el 'find --exec' anterior con el 'eliminar destino'. Alguien quiere probar?
MastroGeppetto
los espacios en blanco en el medio deben mitigarse poniendo "$ f" en comillas dobles Así es como lo uso con "find & xargs" en lugar de "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-destination $ (readlink "{ } ")" {} "'Lo publiqué como una respuesta separada para la visibilidad. superuser.com/a/1329543/499386
Diego
2
find .-type l -exec cp --dereference --recursive '{}''{}'.dereferenced \;
Hará una copia de cada archivo / carpeta con enlace simbólico <filename>.dereferenced, que es más seguro (si es menos conveniente) que simplemente reemplazarlos directamente. Mover los datos copiados a los nombres de archivo de los enlaces simbólicos se deja como ejercicio para el lector.
Una pequeña mejora ayudará a encontrar enlaces simbólicos: para lnk en `find. -tipo l`; do src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; hecho (no probado con la jerarquía, sin embargo, tenga cuidado con los backticks)
Roman Susi
1
Tuve el mismo problema con la copia de enlaces de gwenview cuando normalmente esperarías que siguiera el enlace y copiara el archivo.
Lo que hice para 'limpiar' el directorio siguiendo todos los enlaces y copiando todos los archivos apuntados al directorio, fue crear un directorio temporal, ejecutar, por ejemplo
"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./"
Esto es demasiado peligroso para poner en un script ya que no hay verificación pero solucionó mi problema.
Respuestas:
Para algunas definiciones de "fácil":
Ejecute este script con nombres de enlaces como argumentos, por ejemplo, a través de
find . -type l -exec /path/tos/script {} +
fuente
"$var"
a"${var}"
es un noop en sh / bash. Eliminé el bashism ([[
), el resto es compatible con POSIX sh.cp
un archivo temporal en el mismo directorio y luegomv -f
ese archivo temporal en el original. Esto debería evitar problemas como personas que se mantienen presionadasCtrl-C
o que el sistema de archivos se llene entre los comandosrm
ycp
(evitando así que incluso los nuevosln
funcionen). Los nombres de archivo temporales son fáciles de detectarls -a
para una limpieza posterior si es necesario.abstarget=$(readlink -f "$link")
lugar del bloque de casos , sino que podría haber sido por razones de portabilidad.Puede ser más fácil usar tar para copiar los datos a un nuevo directorio.
Podrías usar algo como esto
fuente
tar -hcf - sourcedir | tar -xf - -C newdir
cp -L
es la solución más simplecp
implementaciones copiarán directorios.Si te entendí correctamente, la
-L
bandera delcp
comando debería hacer exactamente lo que quieres.Simplemente copie todos los enlaces simbólicos y los reemplazará con los archivos a los que apuntan.
fuente
cp -L files tmp/ && rm files && cp tmp/files .
si aclaras, probablemente ayudarás a más personas ..."fácil" será una función tuya, muy probablemente.
Probablemente escribiría un script que usa la utilidad de línea de comando "find" para encontrar archivos vinculados simbólicamente, luego llama a rm y cp para eliminar y reemplazar el archivo. Probablemente harías bien en hacer que la acción llamada por find compruebe que queda suficiente espacio libre antes de mover también el enlace sym.
Otra solución puede ser montar el sistema de archivos en cuestión a través de algo que oculta los enlaces simbólicos (como samba), luego simplemente copie todo. Pero en muchos casos, algo así introduciría otros problemas.
Una respuesta más directa a su pregunta es probablemente "sí".
Editar: según la solicitud de información más específica. De acuerdo con la página de manual de find , este comando enumerará todos los archivos de enlace sym en una profundidad de 2 directorios, desde /:
( esto se encontró aquí )
Para obtener find para ejecutar algo al encontrarlo:
Creo que llamará a un script que acabo de inventar y pasará el nombre de archivo que acaba de encontrar. Alternativamente, puede capturar la salida de búsqueda al archivo (use "find [blah]> symlinks.data", etc.) y luego pasar ese archivo a un script que haya escrito para manejar la copia sobre el original con gracia.
fuente
-exec ./ReplaceSymLink.sh {} \;
Este es el oneliner que he usado: suponga que todos los archivos locales son enlaces a otro archivo en "fuente". Puede refinar la selección de archivos con patrones o "buscar". Por favor, comprenda antes de usar.
Espero que esto ayude
fuente
Hará una copia de cada archivo / carpeta con enlace simbólico
<filename>.dereferenced
, que es más seguro (si es menos conveniente) que simplemente reemplazarlos directamente. Mover los datos copiados a los nombres de archivo de los enlaces simbólicos se deja como ejercicio para el lector.fuente
Usando algunas de las ideas anteriores, el siguiente comando reemplazará recursivamente cada enlace simbólico con una copia del original:
fuente
basado en /superuser//a/1301199/499386 de MastroGeppetto
fuente
Hay muchas buenas respuestas allí, pero desde que estabas buscando algo fácil
fuente
Tuve el mismo problema con la copia de enlaces de gwenview cuando normalmente esperarías que siguiera el enlace y copiara el archivo.
Lo que hice para 'limpiar' el directorio siguiendo todos los enlaces y copiando todos los archivos apuntados al directorio, fue crear un directorio temporal, ejecutar, por ejemplo
Esto es demasiado peligroso para poner en un script ya que no hay verificación pero solucionó mi problema.
fuente
fuente
Hice una versión de una línea, ya que mi hotel web no permitía bash-scripts y funcionó bien para mí:
fuente