Commande CP: copier correctement les dossiers de fichiers vers * nix



Cet article révélera certaines choses non évidentes liées à l'utilisation de caractères génériques lors de la copie, le comportement ambigu de la commande cp lors de la copie, ainsi que des moyens de copier correctement un grand nombre de fichiers sans omissions ni plantages.

Supposons que nous devons tout copier du dossier / source vers le dossier / cible.

La première chose qui me vient à l'esprit est:

 cp /source/* /target 

Corrigez immédiatement cette commande pour:

 cp -a /source/* /target 

Le commutateur -a ajoutera une copie de tous les attributs, droits et ajoutera la récursivité. Lorsqu'une reproduction exacte des droits n'est pas requise, le commutateur -r suffit.

Après la copie, nous constatons que tous les fichiers n'ont pas été copiés - les fichiers à partir d'un point comme ont été ignorés:

.profile
.local
.mc

et similaires.

Pourquoi est-ce arrivé?

Parce que les caractères génériques traitent le shell ( bash dans un cas typique). Par défaut, bash ignorera tous les fichiers commençant par des points, car il les traite comme masqués. Pour éviter ce comportement, nous devons changer le comportement de bash utilisant la commande:

 shopt -s dotglob 

Pour enregistrer ce changement de comportement après un redémarrage, vous pouvez créer le fichier wildcard.sh avec cette commande dans le dossier /etc/profile.d (votre distribution peut avoir un dossier différent).

Et s'il n'y a aucun fichier dans le répertoire source, le shell ne peut rien remplacer par l'astérisque et la copie échouera également. Dans ce cas, il existe des nullglob failglob et nullglob . Nous devons définir failglob , ce qui empêchera l'exécution de la commande. nullglob ne fonctionnera pas, car il convertit une chaîne avec des caractères génériques qui n'ont pas trouvé de correspondances en une chaîne vide (de longueur nulle), ce qui provoquera une erreur pour cp .

Cependant, s'il y a des milliers de fichiers et plus dans le dossier, l'approche utilisant des caractères génériques doit être complètement abandonnée. Le fait est que bash étend les caractères génériques en une très longue ligne de commande comme:

 cp -a /souce/a /source/b /source/c …… /target 

Il y a une limitation sur la longueur de la ligne de commande, que nous pouvons découvrir en utilisant la commande:

 getconf ARG_MAX 

Obtenez la longueur maximale de la ligne de commande en octets:

 2097152 

Ou:

 xargs --show-limits 

Nous obtenons quelque chose comme:

 …. Maximum length of command we could actually use: 2089314 …. 

Alors, faisons sans aucun caractère générique.

Écrivons juste

 cp -a /source /target 

Et ici, nous rencontrerons l'ambiguïté du comportement de cp . Si le dossier / target n'existe pas, nous obtenons ce dont nous avons besoin.

Cependant, si le dossier cible existe, les fichiers seront copiés dans le dossier / target / source.

Nous ne pouvons pas toujours supprimer le dossier / target à l'avance, car il peut contenir les fichiers dont nous avons besoin et notre objectif, par exemple, est d'ajouter des fichiers à / target avec des fichiers de / source.

Si les dossiers source et de destination étaient nommés de la même manière, par exemple, nous copierions de / source vers / home / source, alors nous pourrions utiliser la commande:

 cp -a /source /home 

Et après avoir copié les fichiers dans / home / source, les fichiers complétés de / source.

Telle est la tâche logique: nous pouvons ajouter des fichiers au répertoire de destination, si les dossiers sont nommés de la même manière, mais s'ils diffèrent, le dossier source sera placé à l'intérieur du récepteur. Comment copier des fichiers de / source vers / cible en utilisant cp sans caractères génériques?

Pour contourner cette limitation nuisible, nous utilisons une solution non évidente:

 cp -a /source/. /target 

Ceux qui connaissent bien DOS et Linux ont déjà tout compris: à l'intérieur de chaque dossier il y a 2 dossiers invisibles "." et "..", qui sont des liens de pseudo-dossiers vers les répertoires actuels et supérieurs.

  • Lors de la copie, cp vérifie l'existence et essaie de créer / cible /.
  • Un tel répertoire existe et c'est / target
  • Fichiers de / source copiés vers / cible correctement.

Ainsi, nous nous accrochons dans un cadre gras dans notre mémoire ou sur le mur:

 cp -a /source/. /target 

Le comportement de cette commande est sans ambiguïté. Tout fonctionnera sans erreur, que vous ayez un million de fichiers ou pas du tout.

Conclusions


Si vous souhaitez copier tous les fichiers d'un dossier vers un autre, nous n'utilisons pas de caractères génériques, au lieu d'eux, il est préférable d'utiliser cp en combinaison avec un point à la fin du dossier source. Cela copiera tous les fichiers, y compris ceux cachés, et n'échouera pas avec des millions de fichiers ou une absence complète de fichiers.

Postface


vmspike a suggéré une variante similaire de la commande:

 cp -a -T /source /target 

Oz_Alex
 cp -aT /source /target 

ATTENTION: le cas de la lettre T compte. Si vous le mélangez, vous obtenez la poubelle complète: le sens de la copie va changer.

Remerciements:

  • Société RUVDS.COM pour son soutien et l'opportunité de publier sur son blog sur Habré.
  • Par image TripletConcept . L'image est très grande et détaillée, vous pouvez l'ouvrir dans une fenêtre séparée.

Erreurs PS Direct que vous remarquez dans PM. J'augmente le karma pour cela.



Source: https://habr.com/ru/post/fr471092/


All Articles