Mover un archivo y reemplazarlo por un enlace simbólico

16

¿Alguien puede darme una orden que:

  • mover un archivo hacia un nuevo directorio
  • y dejar un enlace simbólico en su ubicación anterior hacia la nueva
Yo B.
fuente

Respuestas:

19

mvmueve un archivo y ln -screa un enlace simbólico, por lo que la tarea básica se lleva a cabo mediante un script que ejecuta estos dos comandos:

#!/bin/sh
mv -- "$1" "$2"
ln -s -- "$2" "$1"

Hay algunas advertencias. Si el segundo argumento es un directorio, mvmovería el archivo a ese directorio, pero ln -screaría un enlace al directorio en lugar de al archivo movido.

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"

Otra advertencia es que el primer argumento ln -ses el texto exacto del enlace simbólico. Es relativo a la ubicación del objetivo, no al directorio donde se ejecuta el comando. Si la ubicación original no está en el directorio actual y el destino no se expresa mediante una ruta absoluta, el enlace será incorrecto. En este caso, la ruta debe reescribirse. En este caso, crearé un enlace absoluto (sería preferible un enlace relativo, pero es más difícil hacerlo bien). Este script supone que no tiene nombres de archivo que terminen en un carácter de nueva línea.

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
case "$original" in
  */*)
    case "$target" in
      /*) :;;
      *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
    esac
esac
ln -s -- "$target" "$original"

Si tiene varios archivos, procéselos en un bucle.

#!/bin/sh
while [ $# -gt 1 ]; do
  eval "target=\${$#}"
  original="$1"
  if [ -d "$target" ]; then
    target="$target/${original##*/}"
  fi
  mv -- "$original" "$target"
  case "$original" in
    */*)
      case "$target" in
        /*) :;;
        *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
      esac
  esac
  ln -s -- "$target" "$original"
  shift
done
Gilles 'SO- deja de ser malvado'
fuente
1
Gracias Gilles, por el guión y las explicaciones. ¡Intentaré entender eso!
Yo B.
Esto debería ser marcado como la respuesta correcta
Sridhar Sarnobat
Para que esta respuesta sea aún más sorprendente, rsync --remove-source-filespodría ser más informativo para los usuarios que están moviendo un archivo grande de un disco, lo que puede llevar algo de tiempo.
Sridhar Sarnobat
Creo que debería llamar a sh con -e para que se rompa en los errores, por ejemplo, si detiene el comando mv porque ya existe un archivo
Alex
2

Pon esto en el archivo .sh y hazlo ejecutable ( chmod +x filename):

#!/bin/bash

mv "$1" "$2"
ln -s "$2" "$1"

Ejemplo de uso:

./test.sh asdf otherdir/asdf

Tenga en cuenta que esto no realiza controles de seguridad, etc. Dependiendo de cuán compleja sea su tarea, esto podría ser suficiente.

MatthewRock
fuente
Gracias Matthew, esto funciona perfectamente cuando se aplica en un archivo. Pero me pueden ayudar a generalizar esto a dos directorios como estos: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. El *no parece estar trabajando con su test.sh. ¿Tienes una solución? Thx
Yo B.
2
El script de @kadok MatthewRock solo funciona para un solo archivo, y el destino debe ser una ruta absoluta o la fuente debe estar en el directorio actual.
Gilles 'SO- deja de ser malvado'
Además, no funcionará si $ 1 es un archivo pero $ 2 es un directorio.
Sridhar Sarnobat
0

Generalmente uso la función de una línea:

function ml() { mkdir -p "$(dirname "$1")" && rsync -aP --no-links "$1" "$2" && ln -sf "$2" "$1" }

El uso es similar a mv o cp:

ml old_file target_dir/new_file_name

Desglosándolo:

  • mkdir -p "$(dirname "$1")" - crea el directorio de destino si aún no existe
    • dirname "$1" - obtenga el componente de directorio de la ruta (elimine el nombre del archivo)
  • rsync -aP --no-links "$1" "$2"- Copie el archivo al destino. Reemplace esto con mv "$1" "$2"si ambos archivos están en el mismo sistema de archivos para un mejor rendimiento.
    • -a- preservar la propiedad y todos los demás permisos. Puede ajustar esto para preservar solo los componentes que desee.
    • -P - Mostrar progreso.
    • --no-links - no copie enlaces: esto significa que puede ejecutar este comando tantas veces como desee en el mismo archivo, y nunca perderá su archivo al sobrescribir accidentalmente su archivo de destino con un enlace simbólico a sí mismo.
  • ln -sf "$2" "$1" - sobrescribe el archivo anterior con un enlace simbólico al archivo nuevo
    • -s - usar enlaces simbólicos
    • -f - sobrescribe el archivo antiguo
usuario60561
fuente