Spostare un file e sostituirlo con un collegamento simbolico


16

Qualcuno può darmi un comando che dovrebbe:

  • sposta un file in una nuova directory
  • e lasciare un collegamento simbolico nella sua posizione precedente verso quello nuovo

Risposte:


19

mvsposta un file e ln -screa un collegamento simbolico, quindi l'attività di base viene eseguita da uno script che esegue questi due comandi:

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

Ci sono alcuni avvertimenti. Se il secondo argomento è una directory, mvil file verrà spostato in quella directory, ma ln -sverrà creato un collegamento alla directory anziché al file spostato.

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

Un altro avvertimento è che il primo argomento ln -sè il testo esatto del collegamento simbolico. È relativo alla posizione della destinazione, non alla directory in cui viene eseguito il comando. Se la posizione originale non si trova nella directory corrente e la destinazione non è espressa da un percorso assoluto, il collegamento sarà errato. In questo caso, il percorso deve essere riscritto. In questo caso, creerò un collegamento assoluto (sarebbe preferibile un collegamento relativo, ma è più difficile ottenere il giusto). Questo script presuppone che non si disponga di nomi di file che terminano con un carattere di nuova riga.

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

Se hai più file, elaborali in un ciclo.

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

1
Grazie Gilles, per la sceneggiatura e le spiegazioni. Proverò a capirlo!
— Yo B.

Questa dovrebbe essere contrassegnata come la risposta giusta
— Sridhar Sarnobat il

Per rendere questa risposta ancora più fantastica, rsync --remove-source-filespotrebbe essere più informativo per gli utenti che stanno spostando un file di grandi dimensioni da un disco, il che potrebbe richiedere del tempo.
— Sridhar Sarnobat,

Penso che dovresti chiamare sh con -e in modo che si rompa sugli errori, ad esempio se interrompi il comando mv perché esiste già un file
— Alex

2

Mettilo nel file .sh e rendilo eseguibile ( chmod +x filename):

#!/bin/bash

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

Esempio di utilizzo:

./test.sh asdf otherdir/asdf

Si noti che ciò non comporta controlli di sicurezza, ecc. A seconda di quanto sia complessa l'attività, ciò potrebbe essere sufficiente.


Grazie Matteo, funziona perfettamente se applicato su un file. Ma si può aiutarmi a generalizzare questo per due directory come questo: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. Il *non sembra di lavorare con il vostro test.sh. Hai una soluzione? Grazie
— Yo B.

2
@kadok Lo script di MatthewRock funziona solo per un singolo file e la destinazione deve essere un percorso assoluto, altrimenti l'origine deve trovarsi nella directory corrente.
— Gilles 'SO- smetti di essere malvagio' il

Inoltre, non funzionerà se $ 1 è un file ma $ 2 è una directory.
— Sridhar Sarnobat,

0

In genere utilizzo questa funzione a una riga:

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

L'utilizzo è simile a mv o cp:

ml old_file target_dir/new_file_name

Abbattendo:

  • mkdir -p "$(dirname "$1")" - crea la directory di destinazione se non esiste già
    • dirname "$1" - ottieni il componente directory del percorso (elimina il nome file)
  • rsync -aP --no-links "$1" "$2"- copia il file sulla destinazione. Sostituiscilo con mv "$1" "$2"se entrambi i file si trovano sullo stesso filesystem per prestazioni migliori.
    • -a- preservare la proprietà e tutte le altre autorizzazioni. È possibile ottimizzare questo per preservare solo i componenti desiderati.
    • -P - mostra progressi.
    • --no-links - non copiare i collegamenti - questo significa che puoi eseguire questo comando tutte le volte che vuoi sullo stesso file e non perderai mai il tuo file sovrascrivendo accidentalmente il tuo file di destinazione con un link simbolico a se stesso.
  • ln -sf "$2" "$1" - sovrascrive il vecchio file con un link simbolico al nuovo file
    • -s - usa collegamenti simbolici
    • -f - sovrascrive il vecchio file
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.