Comment copier un dossier de manière récursive de manière idempotente en utilisant cp?
On décembre 1, 2020 by adminQuand jutilise
cp -R inputFolder outputFolder
le résultat est dépendant du contexte :
- si
outputFolder
nexiste pas, il sera être créé et le chemin du dossier cloné seraoutputFolder
. - si
outputFolder
existe, alors le clone créé sera beoutputFolder/inputFolder
Cest horrible , parce que je veux créer un script dinstallation, et si lutilisateur lexécute deux fois par erreur, il aura outputFolder
créé la première fois, puis lors de la deuxième exécution, tout le contenu sera être recréé dans outputFolder/inputFolder
.
- Je veux toujours le premier comportement: créer un clone à côté de loriginal (en tant que frère ou sœur).
- Je souhaite utiliser
cp
pour être portable (par exemple MINGW ne avoirrsync
expédié) - Jai vérifié
cp -R --parents
mais cela recrée le chemin tout en haut de larborescence des répertoires (donc le clone ne sera pasoutputFolder
maissome/path/outputFolder
) -
--remove-destination
ou--update
dans le cas 2 ne change rien, les choses sont toujours copiées dansoutputFolder/inputFolder
Est il existe un moyen de le faire sans vérifier dabord lexistence du outputFolder
(si le dossier nexiste pas alors …) ou en utilisant rm -rf outputFolder
?
Quelle est la manière UNIX portable et convenue de faire cela?
Commentaires
Réponse
Utilisez plutôt ceci:
cp -R inputFolder/. outputFolder
Cela fonctionne exactement de la même manière que, disons, cp -R aaa/bbb ccc
fonctionne: si ccc
nexiste pas alors il » s créé en tant que copie de bbb
et de son contenu; mais si ccc
existe déjà, alors ccc/bbb
est créé comme copie de bbb
et de son contenu .
Pour presque toutes les instances de bbb
, cela donne le comportement indésirable que vous avez noté dans votre question. Cependant, dans cette situation spécifique, bbb
est simplement .
, donc aaa/bbb
est vraiment aaa/.
, qui à son tour nest en réalité que aaa
mais sous un autre nom. Nous avons donc ces deux scénarios:
-
ccc
nexiste pas:La commande
cp -R aaa/. ccc
signifie » créerccc
et copier le contenu deaaa/.
dansccc/.
, cest-à-dire copiezaaa
dansccc
. -
ccc
existe:La commande
cp -R aaa/. ccc
signifie » copier le contenu deaaa/.
dansccc/.
, cest-à-dire copiezaaa
dansccc
.
Commentaires
- Hein, ce ‘ est un nouveau pour moi, mais cela semble fonctionner! Est-ce documenté quelque part?
- Jai ‘ testé le
inputFolder/.
au lieu deinputFolder
et en effet cela fonctionne pour moi sur Windows / Git Bash. (Cela ne fonctionne cependant pas avec juste un/
de fin, jai aussi besoin du point après la barre oblique).Jai donné +1 car ‘ est intéressant, bien que ‘ soit probablement un peu trop délicat pour lutiliser en code public 🙂 - @IlmariJaronen, cela na ‘ pas besoin dêtre documenté explicitement. Suivez lexplication et vous ‘ verrez comment il » suit les règles » .
Réponse
Ne copiez pas le dossier, copiez uniquement le contenu:
## Create the target directory. The -p suppresses error messages ## if the directory already exists mkdir -p outputFolder ## Copy the contents recursively, this will not recreate the parent cp -R inputfolder/* outputfolder/
De cette façon, vous vous assurez tous les deux que le répertoire cible est créé la première fois que le script sexécute et évitez le problème lors de son exécution une deuxième fois.
Chris Down souligne très correctement que dans bash, cela ignorera les fichiers dont le nom commence par .
. Pour éviter cela , vous pouvez exécuter shopt -s dotglob
avant dexécuter la commande ci-dessus.
Les deux -p
pour mkdir
et -R
pour cp
sont définis par POSIX donc cela devrait être parfaitement portable.
Commentaires
- Remarque: cela na pas permis de ‘ copier les fichiers commençant par
.
. Dans bash, vous pouvez utiliserdotglob
pour cela. - Notez que cette méthode est susceptible déchouer si le nombre dentrées de répertoire dans inputfolder est important, car lexpansion de glob pourrait dépasser la longueur maximale de la ligne de commande.
Réponse
Essayez la -T
sur cp
. Cela existe dans GNU coreutils cp
version 8.22; il nest peut-être pas portable en dehors de ça.
Commentaires
- Ouais, il semble que cest exactement ce que je voulais:
cp -T
(cp --no-target-directory
). unix.stackexchange.com/questions/94831/… Malheureusement, ma version decp
est beaucoup plus ancien. - +1 Utilisé juste aujourdhui.
-u
est une excellente option à ajouter pour le rendre paresseux.
Réponse
Vous pouvez également utiliser rsync
:
rsync -uav inputFolder/ outputFolder/
(notez les barres obliques, surtout après la première )
Réponse
Vous pouvez utiliser loption -t
de cp
commande comme:
cp -R inputFolder -t outputFolder
maintenant si le dossier cible nexiste pas, il lancera une erreur:
cp: failed to access ‘outputFolder’: No such file or directory
note ci-dessus, la commande copiera inputFolder
avec son contenu (et pas seulement son contenu)
si vous le souhaitez copier uniquement le contenu de inputFolder
cela devient un peu délicat (car vous devez être prudent lorsque vous utilisez le globbing shell tout en utilisant un astérisque *)
cp -R -t outputFolder/ -- inputFolder/*
maintenant, si le dossier cible nexiste pas, il générera une erreur:
cp: failed to access ‘outputFolder’: No such file or directory
fonctionne avec cp (GNU coreutils) 8.23
Réponse
À mon avis, il ny a rien de plus simple et de plus portable que rm -rf outputFolder
. Donc, je men tiens toujours à ça. Je comprends que votre question est différente, mais je pense que cest la meilleure pratique.
Commentaires
- Cela échoue sil y avait des autorisations ou des propriétés spécifiques sur la cible à conserver. Ou sil sagissait dun lien symbolique.
- La question veut que le résultat de
cp
soit le même, à la fois lorsque le répertoire nexiste pas et quand il existe. Alors, de quoi parlez-vous? - La commande
cp
telle que donnée par lOP ne ‘ garde pas les permissions (ou horodatages).
mv
de déplacer une collection de fichiers dans un seul fichier régulier?rsync
?cp
, la tuyauterie entre deux commandestar
est un bon moyen fiable de copier des arbres.rsync
livré.tar -C input -cf - . | tar -C output -xf -
fonctionne.-C
change le répertoire de travail, mais ce nest pas une option standard, donc si ‘ nest pas pris en charge, vous devez exécuter les deux tars dans les bons répertoires de travail pour commencer, par exemple( cd input && tar -cf - . ) | ( cd output && tar -xf - )
Cependant, si vous ‘ travaillez avec Windows, jutiliserais simplement la réponse de roaima ‘ .