Déplacer un fichier et le remplacer par un lien symbolique

16

Quelqu'un peut-il me donner une commande qui:

  • déplacer un fichier vers un nouveau répertoire
  • et laisser un lien symbolique dans son ancien emplacement vers son nouveau
Yo B.
la source

Réponses:

19

mvdéplace un fichier et ln -scrée un lien symbolique, de sorte que la tâche de base est accomplie par un script qui exécute ces deux commandes:

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

Il y a quelques mises en garde. Si le deuxième argument est un répertoire, il mvdéplacerait le fichier dans ce répertoire, mais ln -scréerait un lien vers le répertoire plutôt que vers le fichier déplacé.

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

Une autre mise en garde est que le premier argument de ln -sest le texte exact du lien symbolique. C'est relatif à l'emplacement de la cible, pas au répertoire où la commande est exécutée. Si l'emplacement d'origine ne se trouve pas dans le répertoire en cours et que la cible n'est pas exprimée par un chemin absolu, le lien sera incorrect. Dans ce cas, le chemin doit être réécrit. Dans ce cas, je vais créer un lien absolu (un lien relatif serait préférable, mais il est plus difficile de bien faire les choses). Ce script suppose que vous n'avez pas de noms de fichiers se terminant par un caractère de nouvelle ligne.

#!/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 vous avez plusieurs fichiers, traitez-les en boucle.

#!/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- arrête d'être méchant'
la source
1
Merci Gilles, pour le script et les explications. Je vais essayer de comprendre ça!
Yo B.
Cela devrait être marqué comme la bonne réponse
Sridhar Sarnobat
Pour rendre cette réponse encore plus impressionnante, cela rsync --remove-source-filespourrait être plus informatif pour les utilisateurs qui déplacent un gros fichier d'un disque, ce qui peut prendre un certain temps.
Sridhar Sarnobat
Je pense que vous devriez appeler sh avec -e pour éviter les erreurs, par exemple si vous arrêtez la commande mv car un fichier existe déjà
Alex
2

Mettez-le dans un fichier .sh et rendez-le exécutable ( chmod +x filename):

#!/bin/bash

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

Exemple d'utilisation:

./test.sh asdf otherdir/asdf

Notez que cela ne fait aucun contrôle de sécurité, etc. Selon la complexité de votre tâche, cela peut être suffisant.

MatthewRock
la source
Merci Matthew, cela fonctionne parfaitement lorsqu'il est appliqué sur un seul fichier. Mais pouvez - vous me aider à deux généralisant ce répertoires comme ceci: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. Le *ne semble pas fonctionner avec votre test.sh. Avez-vous une solution de contournement? Thx
Yo B.
2
Le script de @kadok MatthewRock ne fonctionne que pour un seul fichier, et la cible doit être un chemin absolu, sinon la source doit se trouver dans le répertoire courant.
Gilles 'SO- arrête d'être méchant'
De plus, cela ne fonctionnera pas si $ 1 est un fichier mais $ 2 est un répertoire.
Sridhar Sarnobat
0

J'utilise généralement la fonction cette ligne:

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

L'utilisation est similaire à mv ou cp:

ml old_file target_dir/new_file_name

Décomposer:

  • mkdir -p "$(dirname "$1")" - créer le répertoire de destination s'il n'existe pas déjà
    • dirname "$1" - récupérer le composant répertoire du chemin (supprimer le nom du fichier)
  • rsync -aP --no-links "$1" "$2"- copiez le fichier vers la destination. Remplacez-le par mv "$1" "$2"si les deux fichiers se trouvent sur le même système de fichiers pour de meilleures performances.
    • -a- conserver la propriété et toutes les autres autorisations. Vous pouvez régler cela pour ne conserver que les composants souhaités.
    • -P - montrer les progrès.
    • --no-links - ne copiez pas les liens - cela signifie que vous pouvez exécuter cette commande autant de fois que vous le souhaitez sur le même fichier, et vous ne perdrez jamais votre fichier en écrasant accidentellement votre fichier de destination avec un lien symbolique vers lui-même.
  • ln -sf "$2" "$1" - écraser l'ancien fichier avec un lien symbolique vers le nouveau fichier
    • -s - utiliser des liens symboliques
    • -f - écraser l'ancien fichier
user60561
la source