Ordner mit mv zusammenführen?

149

Wenn ich mveinen Ordner namens "folder" in ein Verzeichnis verschiebe, das bereits "folder" enthält, werden sie dann zusammengeführt oder ersetzt?

Dominique
quelle

Antworten:

120

mvVerzeichnisse 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 --forceOption verwenden.


Sie können dies mit anderen Tools umgehen (z. B. rsync, findoder sogar cp), aber Sie müssen die Auswirkungen sorgfältig abwägen:

  • rsynckann den Inhalt eines Verzeichnisses in ein anderes zusammenführen (idealerweise mit der Option --remove-source-files1 , um nur die Quelldateien sicher zu löschen, die erfolgreich übertragen wurden, und mit der üblichen Berechtigungs- / Besitz- / Zeitbewahrungsoption, -awenn Sie dies wünschen)
    aber dies ist ein vollständiger Kopiervorgang und kann daher sehr festplattenintensiv sein.
  • Derzeit bevorzugte Option: Sie können kombinieren rsync‚s --link-dest=DIROption (Hardlinks anstelle des Kopierens Dateiinhalte zu erstellen, wo möglich) und --remove-source-fileseine semantische sehr ähnlich zu einem regulären zu bekommen mv.
    Dazu --link-destmuss ein absoluter Pfad zum Quellverzeichnis (oder ein relativer Pfad vom Ziel zur Quelle ) angegeben werden.
    ... aber dies wird --link-destauf 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 .
  • Sie können verwendenfind die Quellverzeichnisstruktur auf das Ziel , um sequentiell neu erstellen, dann einzeln die tatsächlichen Dateien bewegen
    ... aber das hat durch die Quelle mehrfach rekursiv und kann während des mehrstufigen Prozess Race Conditions (neue Verzeichnisse an der Quelle erzeugt wird begegnen )
  • cpkann 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)
    aber dies leidet erneut unter einer möglichen Racebedingung (neue Dateien an der Quelle werden gelöscht, obwohl sie im vorherigen Schritt nicht kopiert wurden)

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-fileskeine Verzeichnisse gelöscht werden. Sie müssen also etwas tun find -depth -type d -empty -delete, um den leeren Quellverzeichnisbaum zu entfernen.

n.st
quelle
Es hört sich so an, als hätten Sie nur eine Implementierung von ausprobiert mv. Diese Antwort wäre besser mit einer breiteren Wahrheit. Linux, BSD und "echtes" Unix oder eine Referenz von POSIX oder SUS.
Warren Young
@WarrenYoung Sie haben Recht, ich habe nur die mvvon Debian verwendete Implementierung ausprobiert - der Schwerpunkt liegt auf ausprobiert , da in der Manpage dieses Verhalten nicht erwähnt wird ...
3.
38
Der Nachteil von rsync ist, dass die Daten tatsächlich kopiert werden, anstatt nur die feste Verbindung zu ändern. Dies ist möglicherweise ressourcenintensiv, wenn Sie mit vielen Daten arbeiten.
Jonathan Mayer
7
@Keith Beachten Sie, dass --deletenur Dateien im Zielverzeichnis gelöscht werden , die im Quellverzeichnis nicht vorhanden sind.
9.
1
@ JonathanMayer rsync als mehrere Hardlink-bezogene Funktionen. Beispielsweise können Sie nur feste Verknüpfungen mit der -HFunktion beibehalten oder Dateien im Ziel mithilfe von fest verknüpfen --link-dest. Lesen Sie jedoch die Manpage, bevor Sie sie verwenden.
Allo
87
rsync -av /source/ /destination/
(after checking)
rm -rf /source/
fazie
quelle
Entfernt dies die Quelldateien wie im Kommentar von n.st?
Dominique
3
Nein, ich würde es aus Sicherheitsgründen vorziehen, in zwei Schritten zu arbeiten. Zusammengeführte und entfernte Quelle ist nicht mehr rückgängig zu machen. Ein zusätzlicher Schritt in n.st anwer ist ebenfalls erforderlich (um Verzeichnisse zu entfernen).
Fazie
3
--remove-source-fileshat den Vorteil, dass nur Dateien entfernt werden, die erfolgreich übertragen wurden. Sie können also findleere Verzeichnisse entfernen, und alles, was nicht übertragen wurde, bleibt erhalten, ohne dass die rsyncAusgabe überprüft werden muss.
3.
4
Aber es bewegt sich nicht wirklich - die Geschwindigkeitsauswirkung ist enorm, wenn große Dateien betroffen sind.
Alex
Sie können jedoch keine reine Verschiebung und Verschmelzung durchführen.
Fazie
64

Sie können die -lOption 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/folderin 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 -POption), je nach Ihren Bedürfnissen.

Kumpelschwimmen
quelle
7
@rautamiekka: Ich nehme an, Sie fragen nach dem Grund für die Verwendung von harten Links. Wenn Sie nicht wissen, was Hardlinks sind und warum Sie sie verwenden sollten, sollten Sie diesen Weg wahrscheinlich nicht einschlagen. Das Erstellen fester Verknüpfungen führt jedoch nicht zu einer vollständigen Kopie, sodass dieser Vorgang um Größenordnungen weniger Zeit in Anspruch nimmt als eine vollständige Kopie. Außerdem würden Sie Hardlinks anstelle von Softlinks verwenden, damit Sie die Quelldateien löschen und trotzdem die richtigen Daten anstelle von Zeigern auf ungültige Pfade haben können. Und cpnicht, rsyncweil jedes System es hat cpund jeder damit vertraut ist.
Palswim
7
Die Brillanz dieser Lösung kann als nicht akzeptierte Antwort gewertet werden. Es ist eine elegante Lösung. Sie erhalten die Zusammenführungsfähigkeit cpmit der Betriebszeit von mv.
TheHerk
2
Wenn Sie wissen, dass Sie keine Dateien verschieben müssen, die bereits auf dem Ziel vorhanden sind, möchten Sie auch hinzufügen-n
ndemou
1
@ Ruslan: Das ist wahr, aber Sie können mit keiner Methode ohne Kopie zwischen Dateisystemen wechseln. Sogar mv /fs1/file /fs2/(zwischen Dateisystemen) führt eine Kopie und dann eine Löschung durch.
Palswim
2
Richtig, aber while mvfunktioniert (vorausgesetzt, das Zielverzeichnis existiert noch nicht), auch wenn es nicht "effizient" ist oder wie auch immer Sie es nennen, cp -rlwird es fehlschlagen.
Ruslan
23

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 mvfolgenden 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
Jonathan Mayer
quelle
Args sind SOURCE, DEST
schuess
Das sieht ziemlich nützlich aus. Ich bin versucht, damit meine Festplatte zu säubern. Können andere Experten dazu Stellung nehmen, bevor ich diesem Skript eine Reihe von Sicherungen anvertraue? :-)
LarsH
Übrigens, wenn Sie das Äquivalent von rsync -u(nur aktualisieren, wenn neuere) tun möchten, können Sie ( mvzumindest in einigen Versionen) auch die -uOption 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.
LarsH
1
Dies kann mit Whitespace nicht gut umgehen. Ich habe es mit einigen Verzeichnissen mit Leerzeichen versucht und endete mit einer unendlichen Reihe verschachtelter Verzeichnisse.
Rofer
16

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/{}'
Juwel
quelle
Das ist interessant, aber nur vage relevant für das Thema und nicht einmal im entferntesten, wonach der Benutzer gefragt hat.
Shadur
17
Tatsächlich macht der Code von Jewel genau das, wonach der Benutzer gefragt hat, mit der Ausnahme, dass fehlende Verzeichnisse erstellt werden. Vielleicht solltest du nochmal schauen?
Jonathan Mayer
3
Ich würde hinzufügen, "-print0" in find und "-0" in xargs zu verwenden, weil es Dateien gibt, die Leerzeichen in den Namen haben. Es gibt auch ein kleines Problem, wenn ein Name Klammern enthält, werden sie nicht verschoben.
Markuz
2
Dies ist viel schneller als rsync für eine kleine Anzahl von Dateien, aber es wird ein neuer Prozess für jede Datei ausgelöst, sodass die Leistung bei einer großen Anzahl kleiner Dateien miserabel ist. @ palswims Antwort leidet nicht unter diesem Problem.
Donnerstag,
2
Der Befehl schlägt fehl, wenn in destbereits 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/.
ceving
3

Eine Möglichkeit, dies zu erreichen, wäre:

mv folder/* directory/folder/
rmdir folder

Solange in folderund keine zwei Dateien denselben Namen haben directory/folder, erzielen Sie dasselbe Ergebnis, dh das Zusammenführen.

Ascheshr
quelle
3
Wie genau funktioniert das rm folder?
JakeGould
5
@JakeGould Überhaupt nicht. :)
n.st
rm folder -fRfunktioniert immer bei mir
Octopus
2
Beachten
2

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: erstellen
  • B: ganzen Block lesen (für Pipe lesen)
  • v: ausführlich
  • f: Zu schreibende Datei
  • x: Extrakt
  • -: stdout / stdin

sourcefolderkann auch sein *(für alles im aktuellen Ordner)

gjs
quelle
Die Angabe f -von tar ist normalerweise nicht erforderlich - standardmäßig wird von stdin / write nach stdout gelesen.
muru
1

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
xer0x
quelle
Diese Lösung entgeht Pfadnamen nicht richtig, seien Sie vorsichtig.
user12439
@ user12439, Ich aktualisiere die Lösung, wenn Sie mir zeigen, welches Teil zu beheben ist.
xer0x
1

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.

simon
quelle
1
OP fragt, was passiert, wenn mvverwendet wird.
don_crissti
0

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)

GitHub Upstream .

Siehe auch: https://stackoverflow.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command

Ciro Santilli ist ein Schauspieler
quelle
0

Dies ist der Befehl zum Verschieben von Dateien und Ordnern an ein anderes Ziel:

$ mv /source/path/folder /target/destination/

Denken Sie daran : mvBefehl 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

Talha Siddiqi
quelle