Quand j'utilise
cp -R inputFolder outputFolder
le résultat est dépendant du contexte:
outputFolder
n'existe pas, il sera créé et le chemin du dossier cloné sera outputFolder
.outputFolder
existe, alors le clone créé sera outputFolder/inputFolder
C'est horrible, parce que je veux créer un script d'installation, et si l'utilisateur l'exé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 à nouveau créé dans outputFolder/inputFolder
.
cp
pour être portable (par exemple, MINGW n'a pas rsync
livré)cp -R --parents
mais cela recrée le chemin tout au long de l'arborescence des répertoires (donc le clone ne sera pas outputFolder
mais some/path/outputFolder
)--remove-destination
ou --update
dans le cas où 2 ne change rien, les choses sont toujours copiées dans outputFolder/inputFolder
Existe-t-il un moyen de le faire sans d'abord vérifier l'existence de outputFolder
(si le dossier n'existe pas alors ...) ou en utilisant rm -rf outputFolder
?
Quelle est la méthode UNIX portable et convenable de le faire?
Utilisez-le à la place:
cp -R inputFolder/. outputFolder
Cela fonctionne exactement de la même manière que, par exemple, cp -R aaa/bbb ccc
fonctionne: si ccc
n'existe pas, il est créé en tant que copie de bbb
et de son contenu; mais si ccc
existe déjà alors ccc/bbb
est créé en tant que 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, le bbb
est juste .
, donc aaa/bbb
est vraiment aaa/.
, qui à son tour est vraiment juste aaa
mais sous un autre nom. Nous avons donc ces deux scénarios:
ccc
n'existe pas:
La commande cp -R aaa/. ccc
signifie "créer ccc
et copier le contenu de aaa/.
en ccc/.
, c'est-à-dire copier aaa
dans ccc
.
ccc
existe:
La commande cp -R aaa/. ccc
signifie "copier le contenu de aaa/.
en ccc/.
, c'est-à-dire copier aaa
dans ccc
.
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 à la fois que le répertoire cible est créé lors de la première exécution du script et évitez le problème lors de sa deuxième exécution.
Chris Down souligne très correctement qu'en bash, cela sautera les fichiers dont le nom commence par un .
. Pour éviter cela, vous pouvez exécuter shopt -s dotglob
avant d'exécuter la commande ci-dessus.
Tous les deux -p
pour mkdir
et -R
pour cp
sont définis par POSIX donc cela devrait être parfaitement portable.
Essaie le -T
option pour cp
. Cela existe dans GNU coreutils cp
version 8.22; il peut ne pas être portable en dehors de cela.
Vous pouvez également utiliser rsync
:
rsync -uav inputFolder/ outputFolder/
(notez les barres obliques, surtout après la première)
À mon avis, il n'y a rien de plus simple et de plus portable que rm -rf outputFolder
. Donc, je m'en tiens toujours à cela. Je comprends que votre question est différente, mais je pense que c'est la meilleure pratique.
Vous pouvez utiliser l'option -t
De la commande cp
comme:
cp -R inputFolder -t outputFolder
maintenant, si le dossier cible n'existe pas, il générera une erreur:
cp: failed to access ‘outputFolder’: No such file or directory
la commande ci-dessus copiera inputFolder
avec son contenu (et pas seulement son contenu)
si vous voulez 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 n'existe pas, il générera une erreur:
cp: failed to access ‘outputFolder’: No such file or directory
fonctionne avec cp (GNU coreutils) 8.23