web-dev-qa-db-fra.com

Pourquoi -r récursif est-il nécessaire lors de la copie d'un répertoire sous Linux?

Ma question est la suivante: pourquoi est-il nécessaire d'utiliser l'indicateur -r (récursif) lors de la copie d'un répertoire? Pourquoi faire ceci:

$ cp -r dir1 copyDir1

Quand ne voudrais-je pas ce comportement lors de la copie d'un répertoire?

Une copie récursive d’un répertoire n’est-elle pas vraiment le comportement "par défaut"; le comportement que nous voulons presque tout le temps?

C'est comme si c'était un drapeau superflu.

47

De la manière dont fonctionnent les systèmes de fichiers, un répertoire n’est pas en réalité un dossier contenant des fichiers, mais plutôt un fichier contenant des pointeurs d’inodes vers des fichiers "enfants" qui y sont connectés. Cela signifie que, du point de vue du système de fichiers, un fichier est un fichier, mais un répertoire est simplement un fichier contenant une liste de fichiers connectés.

Donc, du point de vue de la ligne de commande, ceci:

$ cp dir1 copyDir1

Cela signifierait essentiellement copier le fichier nommé dir1 dans un nouveau fichier nommé copyDir1. Et en ce qui concerne le système de fichiers, dir1 n’est en tout cas qu’un fichier; le fait qu’il s’agisse d’un "répertoire" ne sera apparent que lorsque le système de fichiers vérifiera réellement dir1 pour voir en quoi consiste réellement cette pile de bits.

L’indicateur -r indique au système de fichiers de dérouler de manière récursive l’arborescence de fichiers/répertoires et de copier tout & tout contenu pouvant constituer un "enfant" de ce fichier dans un nouvel emplacement.

Maintenant, pour ce qui est de savoir pourquoi cela peut sembler superflu ou redondant, cela revient en réalité à des méthodes historiques de gestion des systèmes de fichiers. En plus de créer un système sûr de tous les types d’erreurs liées à l’utilisateur; accidentelle ou intentionnelle.

Cela veut dire, disons que vous avez un fichier ~/bin dans votre répertoire personnel que vous voulez copier mais que vous avez accidentellement oublié le ~ - parce que vous êtes un humain et que vous faites des erreurs - alors c’est juste /bin comme ceci:

cp /bin/ ~/copy_of_bin

Le "filet de sécurité" de /bin étant un répertoire associé à la nécessité de l'indicateur -r, vous éviterez de copier accidentellement la racine binaire complète du système sur lequel vous vous trouvez dans votre répertoire personnel. Si ce filet de sécurité n'existait pas, un désastre mineur, voire majeur serait survenu.

La logique est que dans les jours qui précèdent les conventions logiques/comportementales pré-GUI (interfaces graphiques) doivent être définies pour éviter que des incidents créés par l'utilisateur puissent potentiellement tuer un système. Et utiliser le drapeau -r en fait maintenant partie.

Si cela vous semble superflu, ne cherchez pas plus loin que le système graphique moderne que vous pouvez placer au-dessus des systèmes de fichiers Linux. Une interface graphique répond aux problèmes de base des utilisateurs de ce type en permettant de glisser-déposer facilement des fichiers et des répertoires.

Mais dans le cas des interfaces textuelles, une bonne partie de "l'expérience utilisateur" au sein de ce monde n'est fondamentalement que des obstacles routiers logiques et hueristiques qui permettent de garder l'utilisateur sous contrôle afin d'éviter un désastre potentiel.

De même, c’est la raison pour laquelle les systèmes de fichiers Linux/Unix ne disposent pas des autorisations 777 et des droits Sudo définis par défaut et de la manière dont les véritables administrateurs système émettent des grincements lorsqu'un utilisateur définit les autorisations 777 ou accorde à chacun des droits Sudo. Ce sont les tâches de base que l’on fait pour s’assurer que le système est stable et aussi "résistant à l’utilisateur" que possible; quiconque se précipitera pour court-circuiter ces conventions causera très probablement des dommages à son système sans même le savoir.

INFORMATIONS COMPLEMENTAIRES: Une autre réponse ici sur le site Unix Stack Exchange explique bien pourquoi un non -La copie récursive d'un répertoire est problématique; l'emphase est à moi.

Eh bien, sans l'indicateur -R, il est uniquement possible de copier des fichiers, car il est plutôt inhabituel que quelqu'un veuille copier un répertoire de manière non récursive: Une copie non récursive ne ferait que donner un deuxième nom à le répertoire, pointant directement sur la même structure de répertoires. Parce que c'est rarement ce que les gens veulent, et qu’il existe en fait un programme séparé qui le fait (ln), une copie non récursive de répertoires n’est pas autorisée.

Ainsi, si un répertoire est simplement un fichier contenant des éléments inode, créer une copie directe de ce fichier équivaudrait à la manière dont un lien réel fonctionnerait. Ce qui n'est pas ce que tout le monde veut.

58
JakeGould

C'est très vrai que c'est le comportement que nous voulons presque tout le temps. Cela ne signifie toutefois pas nécessairement que la copie récursive devrait être le comportement par défaut.

Je pense que les raisons cp agissent comme si elles avaient des racines dans la philosophie Unix. Unix favorise les programmes qui font une chose et le font bien , ainsi que les programmes qui sont simple à la fois en interface et en implémentation (parfois appelé pire c'est mieux ).

La pièce maîtresse du puzzle consiste à réaliser que cp ne copie pas les répertoires - cp copie les fichiers (et uniquement ). Si vous souhaitez copier un répertoire, cp s’appelle de manière récursive afin de copier les fichiers de chaque répertoire.

Bien sûr, la différence entre "copier des répertoires" et "copier des fichiers de manière récursive" n’est absolument rien, du point de vue de l’utilisateur, mais le fait d’avoir cette interface aide l’implémentation à rester simple .

Si vous avez rendu cp capable de copier des répertoires, vous seriez bientôt tenté d'ajouter davantage de fonctionnalités utiles uniquement pour les répertoires. Par exemple, vous pouvez copier uniquement les noms de fichiers terminés par .sh. Inévitablement, cela conduit à la gonflement et au fluage caractéristique que nous sommes habitués dans d’autres systèmes d’exploitation - logiciels lents, complexes et sujets aux erreurs.

Avoir -r aide également l'utilisateur à comprendre ce qui se passe réellement sous l'interface. Un des effets secondaires intéressants de cette méthode est que l’apprentissage du concept d’opération récursive vous épargnera du travail lorsque vous en apprendrez sur d’autres outils qui le prennent en charge (comme grep, par exemple).


Certaines personnes vous diront certainement que l'exposition des détails d'implémentation à l'utilisateur est incorrecte et qu'avoir plus de fonctionnalités est satisfaisante . Mon intention ici est simplement d’expliquer la raison de ce comportement, je ne vais donc pas essayer de discuter d’une façon ou d’une autre.

19
goncalopp

Les interactions avec les répertoires vous permettent de savoir que vous interagissez avec un répertoire et non pas avec un seul fichier.

Par exemple:

$ tree
.
└── folder1
    └── sub1
        └── subsub1

3 directories, 0 files
$
$ cp folder1/ folder2
cp: folder1/ is a directory (not copied).
$
$ mkdir blah
$ cp blah/ blah2
cp: blah/ is a directory (not copied).
$ rm blah/
rm: blah/: is a directory

Donc, si vous voulez réussir la copie d'un dossier, puisqu'il implique à la fois le dossier et les objets liés au référencement du dossier, vous devez le traiter comme s'il s'agissait d'une collection de fichiers:

$ cp -r folder1/ folder2
$ rm -rf folder1
5
mbb

La modification de la valeur par défaut aurait pour conséquence que des milliers de scripts Shell seraient interrompus. Ceci conduit aux exigences POSIX et SUS du comportement par défaut bien connu.

La raison en est le développement historique des commandes cp, ln et mv (le même binaire sur la plupart des anciens systèmes UNIX) dans diverses branches UNIX. Lorsque -r est apparu (cp au début n’avait pas la possibilité de copier des répertoires; , voici une première page de manuel de cp sans -r ou -R), il y avait diverses différences. dans la gestion de fichiers spéciaux, de liens symboliques et d’autres aléas du système de fichiers.

De Spécifications du groupe ouvert Open Issue Issue 7 :

Les versions antérieures de cette norme incluaient la prise en charge de l'option -r pour la copie des hiérarchies de fichiers. L'option -r est une pratique historique sur les systèmes BSD et dérivés de BSD. Cette option n'est plus spécifiée par POSIX.1-2008 mais peut être présente dans certaines implémentations. L'option -R a été ajoutée en tant que synonyme proche de l'option -r, sélectionnée pour la cohérence avec toutes les autres options de ce volume de POSIX.1-2008 effectuant une descente de répertoire récursive.

La différence entre -R et l'option -r supprimée réside dans le traitement par cp de types de fichiers autres que normal et directory. Elle a été définie par la manière dont l'option traitait les fichiers spéciaux pour permettre à la fois les implémentations historiques et celles qui choisissaient de prendre en charge -r avec les mêmes capacités que -R défini par ce volume de POSIX.1-2008. L'option -r d'origine, pour des raisons historiques, ne traitait pas les fichiers spéciaux différemment des fichiers normaux, mais lisait toujours le fichier et en copiait le contenu. Cela posait des problèmes évidents en présence de types de fichiers spéciaux; par exemple, les périphériques de caractères, les FIFO et les sockets.

En fait, vous verrez toujours des personnes qui utilisent régulièrement:

cd dir1 ; tar -cf - . | (cd dir2 ; tar -xpf -)

Parce qu'ils ne croient pas que l'implémentation cp -r sera ce à quoi ils sont habitués sur une machine arbitraire; Ou parce qu'ils veulent le comportement tar.

3
kael

Il s’agit peut-être d’une interface sous-optimale aujourd’hui, mais c’est une décision qui a été prise vers 1970 lors de la conception d’UNIX, alors que le disque coûtait considérablement plus cher. Des millions de scripts Shell en dépendent, et il est beaucoup trop tard pour le changer.

Voir cet article pour les informations de conception d'origine.

3
pjc50

L’avantage évident de l’indicateur -r est que vous pouvez cp * /target/dir copier uniquement tous les fichiers du répertoire source dans le répertoire cible, en omettant (avec toutefois un avertissement). ) tous les répertoires qu'il contient. cp -r * /target/dir copierait tout à la place, y compris les sous-répertoires.

3
Interneci

Vous avez besoin de cet indicateur uniquement lorsque cp est une commande permettant de copier des fichiers et des répertoires , et pas uniquement des répertoires.

S'il existait une commande spéciale pour la copie de répertoires, le comportement "par défaut" serait sûrement une copie récursive.

2
duDE

Comme d'autres l'ont mentionné, un répertoire est fondamentalement juste un autre type de fichier (par opposition à un fichier normal), qui "contient" généralement (pointe vers) d'autres fichiers. Il pourrait contenir des sous-répertoires, pour lesquels la même chose s'applique ...

Donc, si vous copiez un répertoire (perspective de l'utilisateur), vous copiez en réalité un groupe de fichiers (perspective du système de fichiers) (fichiers normaux, fichiers de répertoires, liens symboliques, ...) et pour chaque fichier de répertoire, vous répétez cela de manière récursive. processus. Puisque la copie d'un répertoire est par définition un processus récursif, l'argument de cp s'appelle --recursive.

Il est bien entendu très facile de créer un raccourci de commande dans votre environnement utilisateur (placez-le dans votre fichier .profile/.bashrc pour le rendre disponible en permanence):

alias cpr='cp -r'

Ou peut-être mieux:

alias cpa='cp -av'

De cette façon, vous pouvez copier un répertoire à l'aide de cpa dir1 copyDir1. Cela imprimera non seulement ce qui est copié, mais appliquera également des autorisations de fichier.

Et comme quelqu'un a mentionné que cp pourrait théoriquement détecter que le fichier source est un répertoire et demander s'il doit le copier de manière récursive, voici une suggestion rapide:

cp()
{
    if [ ! -e "$1" ]; then
        echo missing source file
        return 1
    fi
    arg="-d --preserve=all -v"
    if [ -d "$1" ]; then
        read -p "Copy directory recursively? " -n 1 -r
        if [ "$REPLY" == "y" ]; then
            arg="$arg -r"
        fi
        echo
    fi
    /usr/bin/cp $arg "$@"
}

Ceci est juste un wrapper cp pas cher. Il conserve toujours toutes les métadonnées (c'est-à-dire copie l'heure de modification du fichier, copie correctement les liens symboliques, etc.) et si vous essayez de copier un répertoire, il vous demande s'il doit le copier (de manière récursive).

1
basic6