web-dev-qa-db-fra.com

Comment forcer 'cp' à écraser le répertoire au lieu d'en créer un autre à l'intérieur?

J'essaie d'écrire un script Bash qui écrasera un répertoire existant. J'ai un répertoire foo/ et j'essaie d'écraser bar/ avec ce dernier. Mais quand je fais ça:

cp -Rf foo/ bar/

un nouveau répertoire bar/foo/ est créé. Je ne veux pas ça. Il y a deux fichiers dans foo/; a et b. Il existe également des fichiers portant le même nom dans bar/. Je souhaite que foo/a et foo/b remplacent bar/a et bar/b.

76
saketrp

Vous pouvez le faire en utilisant l’option -T dans cp.
Voir la page Man pour cp.

-T, --no-target-directory
    treat DEST as a normal file

Ainsi, selon votre exemple, voici la structure du fichier.

$ tree test
test
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Vous pouvez voir la différence évidente lorsque vous utilisez -v pour Verbose.
Lorsque vous utilisez uniquement l'option -R.

$ cp -Rv foo/ bar/
`foo/' -> `bar/foo'
`foo/b' -> `bar/foo/b'
`foo/a' -> `bar/foo/a'
 $ tree
 |-- bar
 |   |-- a
 |   |-- b
 |   `-- foo
 |       |-- a
 |       `-- b
 `-- foo
     |-- a
     `-- b
3 directories, 6 files

Lorsque vous utilisez l'option -T, il écrase le contenu, traitant la destination comme un fichier normal et non un répertoire.

$ cp -TRv foo/ bar/
`foo/b' -> `bar/b'
`foo/a' -> `bar/a'

$ tree
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Cela devrait résoudre votre problème.

93
Saurabh Meshram

Faites-le en deux étapes.

rm -r bar/
cp -r foo/ bar/
34
Jonathan Wheeler

Si vous voulez vous assurer que bar/ finit par être identique à foo/, utilisez rsync à la place:

rsync -a --delete foo/ bar/

Si seules quelques modifications ont été apportées, l'exécution sera beaucoup plus rapide que la suppression et la recopie de tout le répertoire.

  • -a est le "mode archive", qui copie fidèlement les fichiers de foo/ dans bar/
  • --delete supprime également les fichiers supplémentaires qui ne figurent pas dans foo/ de bar/, en s'assurant que bar/ finit par être identique.
  • Si vous voulez voir ce qu’il fait, ajoutez -vh pour les commentaires détaillés et lisibles par l’homme.
  • Remarque: la barre oblique après foo est obligatoire, sinon rsync copiera foo/ dans bar/foo/ plutôt que de remplacer bar/ lui-même.
    • (Les barres obliques après les répertoires dans rsync sont source de confusion; si cela vous intéresse, voici le scoop. Ils indiquent à rsync de se référer au conten du répertoire plutôt qu'au répertoire lui-même Donc, pour écraser du conten de foo/ sur le contenu de bar/, nous utilisons une barre oblique sur les deux. C'est déroutant, car cela ne fonctionnera pas comme prévu avec une barre oblique. on ni, cependant; rsync interprète sournoisement le chemin de destination comme s'il comportait une barre oblique, même s'il respecte l'absence de barre oblique sur le chemin source. Nous avons donc besoin d'une barre oblique sur le chemin source pour faites-la correspondre à la barre oblique ajoutée automatiquement sur le chemin de destination, si nous voulons copier le conten de foo/ dans bar/, plutôt que le répertoire foo/ lui-même atterrissage dans bar/ en tant que bar/foo.)

rsync est très puissant et utile, si vous êtes curieux, cherchez ce qu'il peut faire d'autre (comme copier sur ssh).

21
Tom Potter

Utilisez cette commande cp:

cp -Rf foo/* bar/
11
anubhava

La commande suivante vérifie que les fichiers dotfiles (fichiers cachés) sont inclus dans la copie:

$ cp -Rf foo/. bar
7
Brynn Mahsman

Très similaire à @ Jonathan Wheeler:

Si vous ne voulez pas vous souvenir, mais ne réécrivez pas bar:

rm -r bar/
cp -r foo/ !$

!$ affiche le dernier argument de votre commande précédente.

3
Michael Dimmitt

Essayez d'utiliser cette commande composée de deux étapes:

rm -rf bar && cp -r foo bar
0
Yahor M

L'opération que vous avez définie est une "fusion" et vous ne pouvez pas le faire avec cp. Cependant, si vous ne recherchez pas la fusion et que vous voulez bien perdre le dossier bar, vous pouvez simplement rm -rf bar supprimer le dossier, puis mv foo bar pour le renommer. Cela ne prendra pas beaucoup de temps car les deux opérations sont effectuées par des pointeurs de fichiers et non par le contenu du fichier.

0
atiyil