Créez les mêmes sous-dossiers dans un autre dossier

8

J'ai un répertoire fooavec des sous-répertoires. Je souhaite créer les mêmes noms de sous-répertoires dans un autre répertoire sans copier leur contenu. Comment puis-je faire cela?

Existe-t-il un moyen d'obtenir une lssortie sous forme de liste d'extension d'accolades?

havakok
la source

Réponses:

11

Essaye ça,

cd /source/dir/path
find . -type d -exec mkdir -p -- /destination/directory/{} \;
  • . -type d Pour répertorier récursivement les répertoires du chemin actuel.
  • mkdir -p -- /destination/directory/{} créer un répertoire à destination.

Cela repose sur un findqui prend en charge l'expansion {}au milieu d'un mot argument.

Siva
la source
6
Cela peut se casser si un nom de fichier ou de dossier au niveau supérieur commence par un tiret. Il omet également les répertoires commençant par un point. Enfin, sachez que toutes les implémentations de ne prennent pas en findcharge l'interpolation de {}dans une autre chaîne.
roaima
1
Et ce n'est pas très évolutif - cela prendra beaucoup de temps s'il y a des millions de répertoires.
Arkadiusz Drabczyk
6
S'il y a beaucoup de choses dans /source/dir/path, cela peut échouer avec une erreur « liste d'arguments trop long » lorsque les essais de shell pour appeler findà l'expansion de *. Mieux vaut simplement l'utiliser .là-bas. De plus, la plupart des findimplémentations permettent {}d'être utilisées même lorsqu'elles sont concaténées avec une autre chaîne, mais ce n'est pas universel.
Kusalananda
1
Vous pouvez utiliser .Au lieu de *dans ce cas. (L'utilisation de xarg pour les performances et la sécurité nécessiterait probablement un script externe pour la concaténation du chemin)
vérifie le
24

En utilisant rsync:

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

Cela recréerait la structure de répertoires de /some/path/dircomme dirdans le répertoire courant, sans copier aucun fichier.

Tout répertoire rencontré dans le chemin source serait créé sur la cible en raison du modèle d'inclusion, mais tout le reste serait exclu. En tant qu'effet secondaire de l'utilisation de -a( --archive), vous obtiendrez les mêmes horodatages sur tous les sous-répertoires de la cible et de la source. Cela fonctionne également pour créer des structures de répertoires locaux à partir de répertoires distants (et vice versa).

Kusalananda
la source
La réponse est presque toujours rsync!
Arronical
8

Vous pouvez utiliser findpour parcourir la structure source et appeler mkdirpour chaque répertoire qu'il rencontre.

Cet exemple, à l'aide de find, copiera la structure de votre répertoire de foovers/tmp/another/

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

La execboucle crée l'ensemble des répertoires en dessous foo, qui est ensuite transmis au mkdir. Si vous ne disposez pas d'une version findqui comprend, +vous pouvez l'utiliser \;au détriment de l'efficacité. Remplacez mkdirpar echo mkdirpour voir ce qui se passerait sans le faire.

roaima
la source
1
Ou avec la boucle évidente,... -exec sh -c 'for dirpath do mkdir -p "/some/path/$dirpath"; done' sh {} +
Kusalananda
exactement avec GNU find (4.7.0-git) cela ne semble pas fonctionner: find: In ‘-exec ... {} +’ the ‘{}’ must appear by itself, but you specified ‘/tmp/another/{}’(il fonctionne avec -exec ... \;, cependant)
ilkkachu
Kusalananda, amélioration prise, merci
roaima
Ilkkachu, je suis sûr d'avoir testé, /path/to/{}mais je ne trouve plus de version où cela fonctionne, j'ai donc adapté la solution. Merci
roaima
3

Avec le shell bash, vous pouvez lui demander l'expansion de chaque répertoire avec l' globstaroption:

shopt -s globstar

puis copiez les répertoires avec une boucle:

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

... ou si vous pensiez qu'ils pourraient tous s'intégrer dans un seul appel à mkdir:

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

C'est la syntaxe du tableau bash qui dit: "prenez chaque élément du $@tableau et remplacez le début de chacun d'eux par /path/to/dest/.

Je ne suis pas au courant d'un moyen d'obtenir lsdirectement une sortie en tant que liste d'extension d'accolade. Si vous avez essayé de masser la sortie de l' **/expansion en une extension d'accolade, vous devez faire attention à:

  • échapper à toutes les virgules dans la sortie
  • échapper à tout {ou ${séquence
  • assurez-vous que la chaîne résultante ne dépasse pas l'espace d'argument de ligne de commande disponible

Je ne le recommanderais pas.

Jeff Schaller
la source
2

La question est une copie intersite de /superuser/1389580/copy-directory-structure-only-at-year-end

Ce type de tâche est un cas d'utilisation classique pour 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)

Ce qui précède crée tous les répertoires sous new-treequi étaient présents sous old-tree. mtreene définit pas d'horodatage sur les répertoires nouvellement créés, donc l'arborescence résultante ressemble à ceci:

$ 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

Si vous préférez que les new-treehorodatages correspondent à ceux de old-tree, exécutez simplement à mtreenouveau. Étant donné que les répertoires existent déjà, mtreemodifieront les horodatages pour correspondre à la spécification source:

$ 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.
la source