Antworten:
mv
Verzeichnisse können nicht zusammengeführt oder überschrieben werden. Die Meldung "mv: kann 'a' nicht nach 'b' verschieben: Verzeichnis nicht leer" wird angezeigt , auch wenn Sie diese --force
Option verwenden.
Sie können dies mit anderen Tools umgehen (z. B. rsync
, find
oder sogar cp
), aber Sie müssen die Auswirkungen sorgfältig abwägen:
rsync
kann den Inhalt eines Verzeichnisses in ein anderes zusammenführen (idealerweise mit der Option --remove-source-files
1 , um nur die Quelldateien sicher zu löschen, die erfolgreich übertragen wurden, und mit der üblichen Berechtigungs- / Besitz- / Zeitbewahrungsoption, -a
wenn Sie dies wünschen) rsync
‚s --link-dest=DIR
Option (Hardlinks anstelle des Kopierens Dateiinhalte zu erstellen, wo möglich) und --remove-source-files
eine semantische sehr ähnlich zu einem regulären zu bekommen mv
. --link-dest
muss ein absoluter Pfad zum Quellverzeichnis (oder ein relativer Pfad vom Ziel zur Quelle ) angegeben werden. --link-dest
auf unbeabsichtigte Weise verwendet (was möglicherweise zu Komplikationen führt oder nicht), erfordert die Kenntnis (oder Bestimmung) des absoluten Pfads zur Quelle (als Argument für --link-dest
) und lässt erneut eine leere Verzeichnisstruktur übrig, die bereinigt werden muss per 1 .find
die Quellverzeichnisstruktur auf das Ziel , um sequentiell neu erstellen, dann einzeln die tatsächlichen Dateien bewegen cp
kann feste Verknüpfungen erstellen (einfach zusätzliche Zeiger auf dieselbe vorhandene Datei setzen), was zu einem Ergebnis führt, das einem Zusammenführen sehr ähnlich ist mv
(und sehr effizient ist, da nur Zeiger erstellt werden und keine tatsächlichen Daten kopiert werden müssen) Welche dieser Problemumgehungen (falls zutreffend) geeignet ist, hängt stark von Ihrem speziellen Anwendungsfall ab.
Denken Sie wie immer nach, bevor Sie einen dieser Befehle ausführen, und erstellen Sie Sicherungskopien.
1: Beachten Sie, dass rsync --remove-source-files
keine Verzeichnisse gelöscht werden. Sie müssen also etwas tun find -depth -type d -empty -delete
, um den leeren Quellverzeichnisbaum zu entfernen.
mv
von Debian verwendete Implementierung ausprobiert - der Schwerpunkt liegt auf ausprobiert , da in der Manpage dieses Verhalten nicht erwähnt wird ...
--delete
nur Dateien im Zielverzeichnis gelöscht werden , die im Quellverzeichnis nicht vorhanden sind.
-H
Funktion beibehalten oder Dateien im Ziel mithilfe von fest verknüpfen --link-dest
. Lesen Sie jedoch die Manpage, bevor Sie sie verwenden.
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
--remove-source-files
hat den Vorteil, dass nur Dateien entfernt werden, die erfolgreich übertragen wurden. Sie können also find
leere Verzeichnisse entfernen, und alles, was nicht übertragen wurde, bleibt erhalten, ohne dass die rsync
Ausgabe überprüft werden muss.
Sie können die -l
Option des Befehls cp verwenden , mit der anstelle von vollständigen Datenkopien feste Verknüpfungen von Dateien auf demselben Dateisystem erstellt werden. Der folgende Befehl kopiert den Ordner source/folder
in einen übergeordneten Ordner ( destination
), der bereits ein Verzeichnis mit dem Namen enthält folder
.
cp -rl source/folder destination
rm -r source/folder
Sie können auch die verwenden -P
( --no-dereference
- oder symbolische Links nicht de-reference) -a
( --archive
- erhalten alle Metadaten enthält auch -P
Option), je nach Ihren Bedürfnissen.
cp
nicht, rsync
weil jedes System es hat cp
und jeder damit vertraut ist.
cp
mit der Betriebszeit von mv
.
-n
mv /fs1/file /fs2/
(zwischen Dateisystemen) führt eine Kopie und dann eine Löschung durch.
mv
funktioniert (vorausgesetzt, das Zielverzeichnis existiert noch nicht), auch wenn es nicht "effizient" ist oder wie auch immer Sie es nennen, cp -rl
wird es fehlschlagen.
Ich würde diese vier Schritte empfehlen:
cd ${SOURCE};
find . -type d -exec mkdir -p ${DEST}/\{} \;
find . -type f -exec mv \{} ${DEST}/\{} \;
find . -type d -empty -delete
oder noch besser, hier ist ein Skript, das eine Semantik ähnlich der mv
folgenden implementiert :
#!/bin/bash
DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"
for SRC in ${@:1:$((${#@} -1))}; do (
cd "$SRC";
find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
find . -type d -empty -delete
) done
rsync -u
(nur aktualisieren, wenn neuere) tun möchten, können Sie ( mv
zumindest in einigen Versionen) auch die -u
Option verwenden. In diesem Fall möchten Sie jedoch möglicherweise nicht leere und leere Quellverzeichnisse löschen, um die Fälle abzudecken, in denen die Dateien im Quellbaum nicht neuer sind. @schuess: Es sieht so aus, als ob es mehrere SOURCE-Argumente geben kann, wenn Sie das brauchen.
Auf diese Weise werden die Verzeichnisse zusammengeführt. Es ist viel schneller als rsync, da es nur die Dateien umbenennt, anstatt sie zu kopieren und dann zu löschen.
cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'
dest
bereits ein Verzeichnis mit demselben Namen wie in ist source
. Und die Dateien werden in einen Ordner verschoben dest
, der sich in befindet source
. Der Befehl tut nichts anderes alsmv source/* source/dest/.
Eine Möglichkeit, dies zu erreichen, wäre:
mv folder/* directory/folder/
rmdir folder
Solange in folder
und keine zwei Dateien denselben Namen haben directory/folder
, erzielen Sie dasselbe Ergebnis, dh das Zusammenführen.
rm folder
?
rm folder -fR
funktioniert immer bei mir
Für die reinsten Kopien verwende ich die Blockread-Kopiermethode tar (-) B.
Beispiel aus dem Quellpfad ('cd' dort, falls erforderlich):
tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)
Dadurch wird eine exakte Kopie des Quellbaums erstellt, wobei der Eigentümer und die Berechtigungen erhalten bleiben. Wenn der Zielordner vorhanden ist, werden die Daten zusammengeführt. Es werden nur Dateien überschrieben, die bereits vorhanden sind.
Beispiel:
$ cd /data1/home
$ tar cBf - jdoe | (cd /data2/home ; tar xBf -)
Wenn der Kopiervorgang erfolgreich ist, können Sie die Quelle ( rm -rf <source>
) entfernen . Dies ist natürlich keine exakte Verschiebung: Die Daten werden kopiert, bis Sie die Quelle entfernen.
Als Option können Sie ausführlich sein (Anzeige der zu kopierenden Datei auf dem Bildschirm), mit -v: tar cBvf -
c
: erstellenB
: ganzen Block lesen (für Pipe lesen)v
: ausführlichf
: Zu schreibende Dateix
: Extrakt-
: stdout / stdinsourcefolder
kann auch sein *
(für alles im aktuellen Ordner)
f -
von tar ist normalerweise nicht erforderlich - standardmäßig wird von stdin / write nach stdout gelesen.
Hier ist ein Skript, das für mich funktioniert hat. Ich bevorzuge mv gegenüber rsync, daher verwende ich Jewel und Jonathan Mayers Lösungen.
#!/bin/bash
# usage source1 .. sourceN dest
length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
pushd $SRC;
find . -type d -exec mkdir -p ${DEST}/{} \;
find . -type f -exec mv {} ${DEST}/{} \;
find . -type d -empty -delete
popd
done
Es ist keine gute Idee, Befehle wie cp oder rsync zu verwenden. Bei großen Dateien dauert es sehr lange. MV ist viel schneller, da es nur die Inodes aktualisiert, ohne die Dateien physisch zu kopieren. Eine bessere Option ist die Verwendung des Dateimanagers Ihres Betriebssystems. Für Opensuse gibt es einen Dateimanager namens Konquerer. Es kann Dateien verschieben, ohne sie tatsächlich zu kopieren. Es hat "Ausschneiden und Einfügen" -Funktion wie in Windows. Wählen Sie einfach alle Unterverzeichnisse in Verzeichnis A aus. Klicken Sie mit der rechten Maustaste und "verschieben" Sie das Verzeichnis B, das möglicherweise Unterverzeichnisse mit demselben Namen enthält. Es wird sie zusammenführen. Es gibt auch Optionen, ob Sie Dateien mit demselben Namen überschreiben oder umbenennen möchten.
mv
verwendet wird.
Python-Lösung
Da ich keine zufriedenstellende vorbestehende Lösung finden konnte, habe ich beschlossen, ein schnelles Python-Skript zu erstellen, um dies zu erreichen.
Diese Methode ist insbesondere deshalb effizient, weil der Quelldateibaum nur einmal von unten nach oben durchsucht wird.
Es wird Ihnen auch ermöglichen, Dinge wie das Überschreiben von Dateien schnell nach Ihren Wünschen zu optimieren.
Verwendungszweck:
move-merge-dirs src/ dest/
verschiebt den gesamten Inhalt von src/*
in dest/
und src/
verschwindet.
Move-Merge-Verzeichnisse
#!/usr/bin/env python3
import argparse
import os
def move_merge_dirs(source_root, dest_root):
for path, dirs, files in os.walk(source_root, topdown=False):
dest_dir = os.path.join(
dest_root,
os.path.relpath(path, source_root)
)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
for filename in files:
os.rename(
os.path.join(path, filename),
os.path.join(dest_dir, filename)
)
for dirname in dirs:
os.rmdir(os.path.join(path, dirname))
os.rmdir(source_root)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Move merge src/* into dest. Overwrite existing files.'
)
parser.add_argument('src_dir')
parser.add_argument('dest_dir')
args = parser.parse_args()
move_merge_dirs(args.src_dir, args.dest_dir)
Dies ist der Befehl zum Verschieben von Dateien und Ordnern an ein anderes Ziel:
$ mv /source/path/folder /target/destination/
Denken Sie daran : mv
Befehl funktioniert nicht, wenn der Ordner zusammengeführt werden (dh eine anderen Ordner mit dem gleichen Namen im Ziel existiert bereits) und das Ziel ist nicht leer .
mv: '/ source / path / folder' kann nicht nach '/ target / destination / folder' verschoben werden: Verzeichnis nicht leer
Wenn der Zielordner leer ist, funktioniert der obige Befehl einwandfrei.
Also, um beide Ordner in jedem Fall zusammenzuführen,
entweder in 2 Befehlen:
$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder
Oder kombinieren Sie beide als einmaligen Befehl:
$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder
mv = verschieben
cp = kopieren
rm = entfernen-r für Verzeichnis (Ordner)
-f Ausführung erzwingen
mv
. Diese Antwort wäre besser mit einer breiteren Wahrheit. Linux, BSD und "echtes" Unix oder eine Referenz von POSIX oder SUS.