Verschieben Sie eine Datei und ersetzen Sie sie durch einen Symlink

16

Kann mir jemand einen Befehl geben, der:

  • Verschieben Sie eine Datei in ein neues Verzeichnis
  • und lassen Sie einen Symlink an seiner alten Position zu seiner neuen
Yo B.
quelle

Antworten:

18

mvVerschiebt eine Datei und ln -serstellt eine symbolische Verknüpfung, sodass die grundlegende Aufgabe von einem Skript ausgeführt wird, das diese beiden Befehle ausführt:

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

Es gibt ein paar Einschränkungen. Wenn das zweite Argument ein Verzeichnis ist, wird mvdie Datei in dieses Verzeichnis verschoben, es wird jedoch ln -seine Verknüpfung zum Verzeichnis und nicht zur verschobenen Datei erstellt.

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

Eine weitere Einschränkung ist, dass das erste Argument für ln -sden genauen Text des symbolischen Links ist. Es ist relativ zum Speicherort des Ziels, nicht zu dem Verzeichnis, in dem der Befehl ausgeführt wird. Wenn sich der ursprüngliche Speicherort nicht im aktuellen Verzeichnis befindet und das Ziel nicht durch einen absoluten Pfad ausgedrückt wird, ist die Verknüpfung falsch. In diesem Fall muss der Pfad neu geschrieben werden. In diesem Fall erstelle ich einen absoluten Link (ein relativer Link wäre vorzuziehen, aber es ist schwieriger, den richtigen zu finden). In diesem Skript wird davon ausgegangen, dass Sie keine Dateinamen haben, die mit einem Zeilenumbruchzeichen enden.

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

Wenn Sie mehrere Dateien haben, verarbeiten Sie diese in einer Schleife.

#!/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 - hör auf böse zu sein'
quelle
1
Vielen Dank, Gilles, für das Drehbuch und die Erklärungen. Ich werde versuchen das zu verstehen!
Yo B.
Dies sollte als die richtige Antwort markiert werden
Sridhar Sarnobat
Um diese Antwort noch attraktiver zu gestalten, ist sie rsync --remove-source-filesmöglicherweise informativer für Benutzer, die eine große Datei von einem Datenträger verschieben, was einige Zeit in Anspruch nehmen kann.
Sridhar Sarnobat
Ich denke, Sie sollten sh mit -e aufrufen, damit es bei Fehlern unterbrochen wird, zum Beispiel, wenn Sie den Befehl mv stoppen, weil bereits eine Datei vorhanden ist
Alex
2

Fügen Sie dies in die .sh-Datei ein und machen Sie sie ausführbar ( chmod +x filename):

#!/bin/bash

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

Anwendungsbeispiel:

./test.sh asdf otherdir/asdf

Beachten Sie, dass dies keine Sicherheitsüberprüfungen usw. durchführt. Je nachdem, wie komplex Ihre Aufgabe ist, kann dies ausreichend sein.

MatthewRock
quelle
Danke Matthew, das funktioniert perfekt, wenn es auf eine Datei angewendet wird. Aber können Sie mir helfen , dies zu zwei Verzeichnissen wie folgt verallgemeinern: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. Der *scheint nicht mit deinem zu arbeiten test.sh. Haben Sie eine Problemumgehung? Thx
Yo B.
2
Das Skript von @kadok MatthewRock funktioniert nur für eine einzelne Datei, und das Ziel muss ein absoluter Pfad sein, oder die Quelle muss sich im aktuellen Verzeichnis befinden.
Gilles 'SO- hör auf böse zu sein'
Es funktioniert auch nicht, wenn $ 1 eine Datei ist, $ 2 jedoch ein Verzeichnis.
Sridhar Sarnobat
0

Ich benutze im Allgemeinen die folgende einzeilige Funktion:

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

Die Verwendung ist ähnlich wie bei mv oder cp:

ml old_file target_dir/new_file_name

Brechen sie ab:

  • mkdir -p "$(dirname "$1")" - Legen Sie das Zielverzeichnis an, falls es noch nicht existiert
    • dirname "$1" - Hole die Verzeichniskomponente des Pfades (entferne den Dateinamen)
  • rsync -aP --no-links "$1" "$2"- Kopieren Sie die Datei auf das Ziel. Ersetzen Sie dies durch, mv "$1" "$2"wenn sich beide Dateien im selben Dateisystem befinden, um eine bessere Leistung zu erzielen.
    • -a- Eigentum und alle anderen Berechtigungen erhalten. Sie können dies so einstellen, dass nur die gewünschten Komponenten erhalten bleiben.
    • -P - Fortschritte zeigen.
    • --no-links - Keine Links kopieren - Das bedeutet, dass Sie diesen Befehl so oft ausführen können, wie Sie möchten, und dass Sie Ihre Datei niemals verlieren, wenn Sie Ihre Zieldatei versehentlich mit einem Symlink zu sich selbst überschreiben.
  • ln -sf "$2" "$1" - Überschreiben Sie die alte Datei mit einem Symlink zur neuen Datei
    • -s - Verwenden Sie symbolische Links
    • -f - überschreibe die alte Datei
user60561
quelle