Différences syntaxiques dans cp -r et comment les surmonter

Disons que nous sums dans un directory vide. Ensuite, les commands suivantes:

mkdir dir1 cp -r dir1 dir2 

Donne deux directorys (vides), dir1 et dir2 , où dir2 a été créé en tant que copy de dir1 . Cependant, si nous faisons ceci:

 mkdir dir1 mkdir dir2 cp -r dir1 dir2 

Ensuite, nous trouvons plutôt que dir1 a été placé dans dir2 . Cela signifie que la même command cp se comporte différemment selon que le directory de destination existe ou non . Si c'est le cas, la command cp fait la même chose:

 mkdir dir1 mkdir dir2 cp -r dir1 dir2/. 

Cela me semble extrêmement contre-intuitif. Je m'attendais à ce que cp -r dir1 dir2 (quand dir2 existe déjà) supprimerait dir2 (et tout contenu) existant et le replaceait par dir1 , puisque c'est le comportement quand cp est utilisé pour deux files. Je comprends que les copys récursives sont elles-mêmes un peu différentes en raison de la façon dont les directorys existent sous Linux (et plus généralement dans les systèmes de type Unix), mais je cherche des explications supplémentaires sur la raison pour laquelle ce comportement a été choisi. Points bonus si vous pouvez me signaler un moyen d'assurer que cp se comporte comme je l'avais prévu (sans devoir, par exemple, tester et supprimer le directory de destination au préalable). J'ai essayé quelques options cp sans aucune chance. Et je suppose que je vais accepter les solutions rsync pour le bien des autres qui se produisent sur cette question qui ne connaissent pas cette command.

Si ce comportement n'est pas universel, je suis sur CentOS, en utilisant bash.

Le comportement que vous searchz est un cas particulier :

 cp -R [-H|-L|-P] [-fip] source_file... target 

[Ce] formulaire est désigné par deux ou plusieurs opérandes où l'option -R est spécifiée. L'utilitaire cp doit copyr chaque file dans la hiérarchie de files racine de chaque file source vers un path de destination nommé comme suit:

  • Si la cible existe et nomme un directory existant, le nom du path de destination correspondant à chaque file de la hiérarchie doit être la concaténation de la cible, un seul caractère <slash> si la cible ne se termine pas par un <slash> et le nom de path du file par rapport au directory contenant le file source.
  • Si la cible n'existe pas et que deux opérandes sont spécifiés, le nom du path de destination correspondant à source_file doit être target; le nom du path de destination correspondant à tous les autres files de la hiérarchie de files doit correspondre à la concaténation de la cible, à un caractère <slash> et au path du file relatif au file source.

Il doit s'agir d'une erreur si la cible n'existe pas et que plus de deux opérandes sont spécifiés …

Par conséquent, je dirais que ce n'est pas possible de faire cp faire ce que vous voulez.


Comme votre comportement attendu est " cp -r dir1 dir2 (quand dir2 existe déjà) supprimerait dir2 (et tout contenu) existant et le replaceait par dir1 ":

 rm -rf dir2 && cp -r dir1 dir2 

Vous n'avez même pas besoin de vérifier si dir2 existe.


La solution rsync serait d'append un fin / vers la source afin qu'il ne copy pas dir1 lui-même dans dir2 mais copy le contenu de dir1 vers dir2 (il gardera toujours les files existants dans dir2 ):

 $ tree dir* dir1 └── test.txt dir2 └── test2.txt 0 directories, 2 file $ rsync -a dir1/ dir2 $ tree dir* dir1 └── test.txt dir2 └── test.txt └── test2.txt 0 directories, 3 files $ rm -r dir2 $ rsync -a dir1/ dir2 $ tree dir* dir1 └── test.txt dir2 └── test.txt 0 directories, 2 files