Erstellen Sie dieselben Unterordner in einem anderen Ordner

8

Ich habe ein Verzeichnis foomit Unterverzeichnissen. Ich möchte die gleichen Unterverzeichnisnamen in einem anderen Verzeichnis erstellen, ohne deren Inhalt zu kopieren. Wie mache ich das?

Gibt es eine Möglichkeit, eine lsAusgabe als Klammererweiterungsliste zu erhalten?

Havakok
quelle

Antworten:

11

Versuche dies,

cd /source/dir/path
find . -type d -exec mkdir -p -- /destination/directory/{} \;
  • . -type d Verzeichnisse im aktuellen Pfad rekursiv auflisten.
  • mkdir -p -- /destination/directory/{} Verzeichnis am Ziel erstellen.

Dies beruht auf einem find, das das Erweitern {}in der Mitte eines Argumentworts unterstützt.

Siva
quelle
6
Dies kann zu Problemen führen, wenn ein Datei- oder Ordnername in der obersten Ebene mit einem Bindestrich beginnt. Außerdem werden Verzeichnisse weggelassen, die mit einem Punkt beginnen. Beachten Sie schließlich, dass nicht jede Implementierung von finddie Interpolation {}in einen anderen String unterstützt.
Roaima
1
Und es ist nicht sehr skalierbar - es wird viel Zeit in Anspruch nehmen, wenn es Millionen von Verzeichnissen gibt.
Arkadiusz Drabczyk
6
Wenn es viele Dinge in /source/dir/path, dann könnte dies mit einer „Argumentliste zu lang“ fail Fehler , wenn die Shell versucht, rufen Sie findmit der Erweiterung der *. Besser nur .dort zu verwenden. Die meisten findImplementierungen können {}auch verwendet werden, wenn sie mit einer anderen Zeichenfolge verknüpft sind, dies ist jedoch nicht universell.
Kusalananda
1
Sie können .Statt *in diesem Fall verwenden. (Die Verwendung von xarg für Leistung und Sicherheit würde wahrscheinlich ein externes Skript für die
Pfadverkettung
24

Verwenden von rsync:

rsync -a --include='*/' --exclude='*' /some/path/dir/ dir

Dies würde die Verzeichnisstruktur /some/path/dirwie dirim aktuellen Verzeichnis neu erstellen , ohne Dateien zu kopieren.

Jedes Verzeichnis, das im Quellpfad gefunden wird, wird aufgrund des Einschlussmusters am Ziel erstellt, alles andere wird jedoch ausgeschlossen. Als Nebeneffekt von using -a( --archive) erhalten Sie für alle Unterverzeichnisse im Ziel dieselben Zeitstempel wie in der Quelle. Dies funktioniert auch zum Erstellen lokaler Verzeichnisstrukturen aus Remote-Verzeichnissen (und umgekehrt).

Kusalananda
quelle
Die Antwort ist fast immer rsync!
Arronical
8

Sie können finddie Quellstruktur durchlaufen und mkdirjedes Verzeichnis aufrufen, auf das sie trifft.

In diesem Beispiel wird mit verwendet find, um Ihre Verzeichnisstruktur von foonach zu kopieren/tmp/another/

( cd foo && find -type d -exec sh -c 'for d do mkdir -p "/tmp/another/$d"; done' sh {} + )

Die execSchleife baut die darunter liegenden Verzeichnisse auf foo, die dann an die übergeben werden mkdir. Wenn Sie keine Version davon haben find, +können Sie diese \;auf Kosten der Effizienz verwenden. Ersetzen Sie mkdirdurch, um echo mkdirzu sehen, was passieren würde, ohne es tatsächlich zu tun.

Roaima
quelle
1
Oder mit der offensichtlichen Schleife... -exec sh -c 'for dirpath do mkdir -p "/some/path/$dirpath"; done' sh {} +
Kusalananda
Genau mit GNU find (4.7.0-git) scheint dies nicht zu funktionieren: find: In ‘-exec ... {} +’ the ‘{}’ must appear by itself, but you specified ‘/tmp/another/{}’(es funktioniert jedoch mit -exec ... \;)
ilkkachu
Kusalananda, Verbesserung genommen, danke
Roaima
Ilkkachu Ich bin sicher, dass ich getestet habe, /path/to/{}aber ich kann jetzt keine Version finden, in der es funktioniert, also habe ich die Lösung angepasst. Vielen Dank
Roaima
3

Mit der Bash-Shell können Sie nach der Erweiterung jedes Verzeichnisses mit der globstarOption fragen :

shopt -s globstar

und kopieren Sie dann die Verzeichnisse mit einer Schleife:

for dir in **/
do
  mkdir -p /path/to/dest/"$dir"
done

... oder wenn Sie dachten, sie würden alle in einen Anruf passen mkdir:

set -- **/
mkdir -- "${@/#//path/to/dest/}"

Das ist die Bash-Array-Syntax, die besagt: "Nehmen Sie jedes Element des $@Arrays und ersetzen Sie den Anfang jedes Elements durch /path/to/dest/.

Mir ist keine Möglichkeit bekannt, lsdirekt als Klammererweiterungsliste auszugeben. Wenn Sie versuchen, die Ausgabe der **/Erweiterung in eine Klammererweiterung zu massieren , müssen Sie Folgendes beachten:

  • Escape-Kommas in der Ausgabe
  • entkomme einer {oder einer ${Sequenz
  • Stellen Sie sicher, dass die resultierende Zeichenfolge den verfügbaren Befehlszeilenargumentraum nicht überschreitet

Ich würde es nicht empfehlen.

Jeff Schaller
quelle
2

Die Frage ist ein Cross-Site-Duplikat von /superuser/1389580/copy-directory-structure-only-at-year-end

Diese Art von Aufgabe ist ein klassischer Anwendungsfall für mtree:

$ mkdir new-tree
$ mtree -cp old-tree | mtree -tdUp new-tree
.:      modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
./bar missing (created)
./bar/bar2 missing (created)
./bar/bar2/bar3 missing (created)
./bar/bar2/bar3/bar4 missing (created)
./foo missing (created)
./foo/foo2 missing (created)
./foo/foo2/foo3 missing (created)

Das obige erstellt alle Verzeichnisse unter new-tree, die unter vorhanden waren old-tree. mtreesetzt jedoch keine Zeitstempel für neu erstellte Verzeichnisse, sodass der resultierende Baum folgendermaßen aussieht:

$ find old-tree new-tree -ls
 20147  1 drwx--x---   4 jim   jim   5 Sep 24 14:27 old-tree
 20048  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/foo
 20363  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/file
 20073  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/foo/foo2
 20074  1 drwx--x---   2 jim   jim   3 Sep 24 14:27 old-tree/foo/foo2/foo3
 20365  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/foo2/foo3/file
 20364  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/foo2/file
 20051  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar
 20077  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar/bar2
 20368  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/file
 20078  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar/bar2/bar3
 20369  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/bar3/file
 20079  1 drwx--x---   2 jim   jim   3 Sep 24 14:27 old-tree/bar/bar2/bar3/bar4
 20370  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/bar3/bar4/file
 20366  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/file
 20362  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/file
134489  1 drwx--x---   4 jim   jim   4 Sep 24 16:34 new-tree
134490  1 drwx--x---   3 jim   jim   3 Sep 24 16:34 new-tree/bar
134491  1 drwx--x---   3 jim   jim   3 Sep 24 16:34 new-tree/bar/bar2
134492  1 drwx--x---   3 jim   jim   3 Sep 24 16:34 new-tree/bar/bar2/bar3
134493  1 drwx--x---   2 jim   jim   2 Sep 24 16:34 new-tree/bar/bar2/bar3/bar4
134494  1 drwx--x---   3 jim   jim   3 Sep 24 16:34 new-tree/foo
134495  1 drwx--x---   3 jim   jim   3 Sep 24 16:34 new-tree/foo/foo2
134496  1 drwx--x---   2 jim   jim   2 Sep 24 16:34 new-tree/foo/foo2/foo3

Wenn Sie möchten, dass die new-treeZeitstempel mit denen in übereinstimmen old-tree, führen Sie sie einfach mtreeerneut aus. Da die Verzeichnisse bereits vorhanden sind, mtreewerden die Zeitstempel an die Quellenspezifikation angepasst:

$ mtree -cp old-tree | mtree -tdUp new-tree
.:      modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
bar:    modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
bar/bar2: 
        modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
bar/bar2/bar3: 
        modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
bar/bar2/bar3/bar4: 
        modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
foo:    modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
foo/foo2: 
        modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
foo/foo2/foo3: 
        modification time (Tue Sep 24 14:27:07 2019, Tue Sep 24 16:34:57 2019, modified)
$ find old-tree new-tree -ls
 20147  1 drwx--x---   4 jim   jim   5 Sep 24 14:27 old-tree
 20048  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/foo
 20363  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/file
 20073  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/foo/foo2
 20074  1 drwx--x---   2 jim   jim   3 Sep 24 14:27 old-tree/foo/foo2/foo3
 20365  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/foo2/foo3/file
 20364  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/foo/foo2/file
 20051  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar
 20077  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar/bar2
 20368  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/file
 20078  1 drwx--x---   3 jim   jim   4 Sep 24 14:27 old-tree/bar/bar2/bar3
 20369  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/bar3/file
 20079  1 drwx--x---   2 jim   jim   3 Sep 24 14:27 old-tree/bar/bar2/bar3/bar4
 20370  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/bar2/bar3/bar4/file
 20366  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/bar/file
 20362  1 -rw-------   1 jim   jim   0 Sep 24 14:27 old-tree/file
134489  1 drwx--x---   4 jim   jim   4 Sep 24 14:27 new-tree
134490  1 drwx--x---   3 jim   jim   3 Sep 24 14:27 new-tree/bar
134491  1 drwx--x---   3 jim   jim   3 Sep 24 14:27 new-tree/bar/bar2
134492  1 drwx--x---   3 jim   jim   3 Sep 24 14:27 new-tree/bar/bar2/bar3
134493  1 drwx--x---   2 jim   jim   2 Sep 24 14:27 new-tree/bar/bar2/bar3/bar4
134494  1 drwx--x---   3 jim   jim   3 Sep 24 14:27 new-tree/foo
134495  1 drwx--x---   3 jim   jim   3 Sep 24 14:27 new-tree/foo/foo2
134496  1 drwx--x---   2 jim   jim   2 Sep 24 14:27 new-tree/foo/foo2/foo3
Jim L.
quelle