Frage 2 Verzeichnisbäume in Linux zusammenführen, ohne zu kopieren?


Ich habe zwei Verzeichnisbäume mit ähnlichen Layouts, d.h.

.
 |-- dir1
 |   |-- a
 |   |   |-- file1.txt
 |   |   `-- file2.txt
 |   |-- b
 |   |   `-- file3.txt
 |   `-- c
 |       `-- file4.txt
 `-- dir2
     |-- a
     |   |-- file5.txt
     |   `-- file6.txt
     |-- b
     |   |-- file7.txt
     |   `-- file8.txt
     `-- c
         |-- file10.txt
         `-- file9.txt

Ich möchte die Verzeichnisbäume dir1 und dir2 zusammenführen, um Folgendes zu erstellen:

 merged/
 |-- a
 |   |-- file1.txt
 |   |-- file2.txt
 |   |-- file5.txt
 |   `-- file6.txt
 |-- b
 |   |-- file3.txt
 |   |-- file7.txt
 |   `-- file8.txt
 `-- c
     |-- file10.txt
     |-- file4.txt
     `-- file9.txt

Ich weiß, dass ich dies mit dem "cp" -Befehl tun kann, aber ich möchte die Dateien verschieben, anstatt zu kopieren, weil die tatsächlichen Verzeichnisse, die ich zusammenführen möchte, wirklich groß sind und viele Dateien (Millionen) enthalten. Wenn ich "mv" verwende, bekomme ich den "File exists" -Fehler wegen in Konflikt stehender Verzeichnisnamen.

UPDATE: Sie können davon ausgehen, dass zwischen den beiden Verzeichnisbäumen keine doppelten Dateien vorhanden sind.


33
2018-06-29 18:05


Ursprung


Sind Sie sicher, dass die Dateinamen nicht doppelt vergeben sind? Was möchten Sie tun, wenn es Dubletten gibt? - Zoredache
Wenn Sie buchstäblich Millionen von Dateien in einem einzigen Verzeichnis haben, sollten Sie aus Performance-Gründen versuchen, die Dateien in separate Unterverzeichnisse aufzuteilen - obwohl dies für die eigentliche Frage irrelevant ist. - DrStalker


Antworten:


rsync -ax --link-dest=dir1/ dir1/ merged/
rsync -ax --link-dest=dir2/ dir2/ merged/

Dies würde harte Verknüpfungen erstellen, anstatt sie zu verschieben. Sie können überprüfen, ob sie korrekt verschoben wurden, und dann entfernen dir1/ und dir2/.


27
2018-06-29 18:44



So'ne Art. Es kopiert nicht wirklich die Festplattenbelegung, es erstellt einfach einen anderen Zeiger auf denselben Festplattenhunk und "kopiert" keine Daten. (Sehen en.wikipedia.org/wiki/Hard_links) Allerdings muss diese Operation einmal pro Datei ausgeführt werden. Aber das ist im Wesentlichen, was alle diese Antworten tun, da Sie nicht einfach ein einzelnes Verzeichnis verschieben können. - Christopher Karel
Da es keinen Overhead beim Kopieren von Dateien gibt, ist dies eine vollkommen akzeptable Lösung. - Tobu
Dies funktioniert jedoch nur, wenn sie sich auf demselben Dateisystem befinden. Würde rsync mit der Option delete eine Verschiebung durchführen, wenn sie sich im selben Dateisystem befänden? (Das heißt, nur die Verzeichnisinformationen ändern, aber die Datei nicht verschieben). - Ronald Pottol
rsync kopiert und löscht dann, wenn es Dateisysteme durchläuft. - karmawhore
Ein Vorbehalt: Machen Sie die --link-dest Pfad absolut oder relativ zu merged/; oder es wird kopiert. - Tobu


Es ist seltsam, dass niemand das bemerkt hat cp hat eine Option -l:

-l, --Link
       Hard-Link-Dateien statt zu kopieren

Sie können etwas wie tun

% mkdir zusammenführen
% cp -rl dir1 / * dir2 / * zusammenführen
% rm -r dir *
% Baumzusammenführung
verschmelzen
.── a
│ ├── Datei1.txt
│ ├── Datei2.txt
│ ├── Datei5.txt
│ └── file6.txt
.── b
│ ├── file3.txt
│ ├── Datei7.txt
│ └── Datei8.txt
C── c
    File── file10.txt
    File── Datei4.txt
    File── file9.txt

13 Verzeichnisse, 0 Dateien

20
2017-12-19 05:46



Dies funktioniert nicht auf verschiedenen Festplatten ... - Alex Leach
Es ist korrekter zu sagen, dass es nicht über Dateisysteme hinweg funktioniert, da Dateisysteme sich über mehrere Festplatten erstrecken können. Auch wenn es darauf ankommt, das Kopieren der Dateien zu vermeiden, ist das eine gute Sache cp -l funktioniert nicht über Dateisysteme hinweg. - lvella
Sie möchten vielleicht verwenden cp -a (Synonym zu cp -RPp) um alle Attribute der Dateien zu behalten und Symlinks zu vermeiden: Hier wird der Befehl cp -al dir1/* dir2/* merge. - tricasse


Sie können dafür das Umbenennen (aka vorname, aus dem Perl-Paket) verwenden. Beachten Sie, dass sich der Name nicht unbedingt auf den Befehl bezieht, den ich außerhalb von debian / ubuntu beschreibe (obwohl es eine einzelne portable Perl-Datei ist, falls Sie sie benötigen).

mv -T dir1 merged
rename 's:^dir2/:merged/:' dir2/* dir2/*/*
find dir2 -maxdepth 1 -type d -empty -delete

Sie haben auch die Möglichkeit, vidir (von moreutils) zu verwenden und die Dateipfade von Ihrem bevorzugten Texteditor aus zu bearbeiten.


5
2018-06-29 18:34





Ich mag rsync und Vorname Lösungen, aber wenn Sie wirklich machen wollen mv mach die Arbeit und

  • Ihre finden weiß es -print0 und -depth,
  • Ihre xargs weiß es -0,
  • du hast drucken,

dann ist es möglich, eine große Anzahl von Dateien mit zufälligem Leerzeichen in ihren Namen zu behandeln, alle mit einem Shell-Skript im Bourne-Stil:

#!/bin/sh

die() {
    printf '%s: %s\n' "${0##*/}" "$*"
    exit 127
}
maybe=''
maybe() {
    if test -z "$maybe"; then
        "$@"
    else
        printf '%s\n' "$*"
    fi
}

case "$1" in
    -h|--help)
        printf "usage: %s [-n] merge-dir src-dir [src-dir [...]]\n" "${0##*/}"
        printf "\n    Merge the <src-dir> trees into <merge-dir>.\n"
        exit 127
    ;;
    -n|--dry-run)
        maybe=NotRightNow,Thanks.; shift
    ;;
esac

test "$#" -lt 2 && die 'not enough arguments'

mergeDir="$1"; shift

if ! test -e "$mergeDir"; then
    maybe mv "$1" "$mergeDir"
    shift
else
    if ! test -d "$mergeDir"; then
        die "not a directory: $mergeDir"
    fi
fi

xtrace=''
case "$-" in *x*) xtrace=yes; esac
for srcDir; do
    (cd "$srcDir" && find . -print0) |
    xargs -0 sh -c '

        maybe() {
            if test -z "$maybe"; then
                "$@"
            else
                printf "%s\n" "$*"
            fi
        }
        xtrace="$1"; shift
        maybe="$1"; shift
        mergeDir="$1"; shift
        srcDir="$1"; shift
        test -n "$xtrace" && set -x

        for entry; do
            if test -d "$srcDir/$entry"; then
                maybe false >/dev/null && continue
                test -d "$mergeDir/$entry" || mkdir -p "$mergeDir/$entry"
                continue
            else
                maybe mv "$srcDir/$entry" "$mergeDir/$entry"
            fi
        done

    ' - "$xtrace" "$maybe" "$mergeDir" "$srcDir"
    maybe false >/dev/null ||
    find "$srcDir" -depth -type d -print0 | xargs -0 rmdir
done

3
2018-06-29 22:42



Sie können xargs anweisen, seine Eingabe in newline zu begrenzen und die Übersetzung zu überspringen. Im folgenden Beispiel würden Sie alle Ihre Torrent-Dateien im aktuellen Verzeichnis finden und löschen, sogar solche mit Unicode-Zeichen oder etwas anderes. find . -name '*.torrent' | xargs -d '\n' rm - PRS


Rohe Gewalt bash 

#! /bin/bash

for f in $(find dir2 -type f)
do
  old=$(dirname $f)
  new=dir1${old##dir2}
  [ -e $new ] || mkdir $new
  mv $f $new
done

Test macht das

# setup 
for d in dir1/{a,b,c} dir2/{a,b,c,d} ; do mkdir -p $d ;done
touch dir1/a/file{1,2} dir1/b/file{3,4} dir2/a/file{5,6} dir2/b/file{7,8} dir2/c/file{9,10} dir2/d/file11

# do it and look
$ find dir{1,2} -type f
dir1/a/file1
dir1/a/file2
dir1/a/file5
dir1/a/file6
dir1/b/file3
dir1/b/file7
dir1/b/file8
dir1/c/file4
dir1/c/file9
dir1/c/file10
dir1/d/file11

2
2018-06-29 19:15



Das OP gab Millionen von Dateien an, was diese Konstruktion wahrscheinlich durchbrechen würde. Außerdem werden Dateinamen mit Leerzeichen, Zeilenumbrüchen usw. nicht korrekt verarbeitet. - Chris Johnsen


Ich musste dies mehrmals für Quellcode-Bäume in verschiedenen Entwicklungsstadien tun. Meine Lösung bestand darin, Git folgendermaßen zu verwenden:

  1. Erstellen Sie ein Git-Repository und fügen Sie alle Dateien aus Verzeichnis1 hinzu.
  2. Verpflichten
  3. Entferne alle Dateien und kopiere Dateien von dir2
  4. Verpflichten
  5. Zeigen Sie Unterschiede zwischen den beiden Festschreibungspunkten an und treffen Sie sorgfältige Entscheidungen darüber, wie die Ergebnisse zusammengeführt werden sollen.

Sie können es mit Verzweigungen und so weiter verfeinern, aber das ist die allgemeine Idee. Und Sie haben weniger Angst davor, es zu stopfen, weil Sie einen vollständigen Schnappschuss von jedem Zustand haben.


0
2018-06-30 00:15