Est-ce que 'rm. *' Supprime le répertoire parent?

53

L'expression .*est développée par bash pour inclure les répertoires courant et parent:

$ ls -la
total 2600
drwxrwxrwx   2 terdon terdon 2162688 Sep 10 16:22 .
drwxr-xr-x 142 terdon terdon  491520 Sep 10 15:34 ..
-rw-r--r--   1 terdon terdon       0 Sep 10 16:22 foo
$ echo .*
. ..

Si je cours rm -rf .*sur mon Debian GNU en utilisant bash, version 4.2.36(1)-releaseet rmde rm (GNU coreutils) 8.13, je reçois ce message:

$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'

Est-ce une chose GNU ou est-ce POSIX? Existe-t-il des systèmes * nix où la commande ci-dessus supprime silencieusement .et ..?

De plus, s'agit-il d'un élément de sécurité du shell ou de la rmcommande elle-même?

terdon
la source
4
Je sais que cette question est dans le contexte de rm, mais je pensais que ce mentionnais tout vaut que vous pouvez toujours avoir des résultats inattendus avec chmod, chown, etc lors de l' appariement .*.
Aaron Copley

Réponses:

59

La dernière version (à compter de 2017) de la spécification POSIX pour l' rmutilitaire est ici (et la précédente est ) et interdit la suppression de .and ...

Si l'un des fichiers, point ou point-point, est spécifié comme étant la partie nom de base d'un opérande (c'est-à-dire le composant final du chemin d'accès) ou si un opérande résout le répertoire racine, rm doit écrire un message de diagnostic en erreur standard et ne rien faire. plus avec de tels opérandes.

Comme indiqué par @jlliagre, la partie concernant /est un ajout dans SUSv4.

La plus ancienne spécification Unix accessible au public que j'ai pu trouver ( XPF4 CAE rev2 (1994)), spécifiait déjà cela .et ..ne pouvait pas être supprimée, bien que les commentaires dans le changelog de GNU fileutils suggèrent que c'était déjà le cas dans les anciennes spécifications POSIX.

Notez qu'il applique dir/..et ../aussi, mais certaines implémentations (y compris ceux certifiés UNIX comme Solaris 11 et Mac OS) ne toujours pas garantie contre rm -rf ../ou rm -rf .*/).

histoire

Unices précoces

L' -roption to a rmété ajoutée dans Unix V3 (1973) bien qu'il ne s'agisse que de supprimer le contenu des répertoires, vous devrez toujours utiliser rmdirpour supprimer des répertoires.

Cela a changé dans Unix V7 (1979, la version qui a également introduit le shell Bourne et dont dérivent la plupart des Unices). rm -rles répertoires maintenant supprimés également et ne supprimeraient pas l’ ..arborescence. La page de manuel dit:

Il est interdit de supprimer le fichier ..simplement pour éviter les conséquences antisociales de faire quelque chose de semblable, par inadvertance rm -r .*.

(Bien que l'on puisse dire que rm -r .*c'est toujours antisocial, car il supprime tout car il .est inclus).

Il acceptait toujours de supprimer .bien que cela ne dissocierait pas les entrées .ou ... Donc, rm -r .était un moyen efficace de vider le répertoire en cours.

Notez également que la sauvegarde était uniquement pour un ..argument littéral , pas pour dir/..ou ./... Donc, rm -rf ./.*toujours supprimer tout ce qui se trouve dans le répertoire parent de manière récursive.

Il est intéressant de voir que c'était déjà pour contourner le bogue / le défaut d'utilisation par lequel les globs pourraient inclure .et ..dans leur développement. Cela a été corrigé dans le shell Forsyth (la base du shell original Minix et de pdksh) à la fin des années 80, zsh(1990) et fish(2005), mais pas dans d’autres shell et en particulier dans le shlangage POSIX qui nécessite l’extension d’ .*inclure .et ..si ils sont retournés par readdir()(ne bashrésout le problème qu'en partie avec le shopt -s dotglobcas où les globs (à l'exception de .xxxceux-ci) n'incluent pas .ou .., et avec ksh, vous pouvez le réparer en procédant de la sorte FIGNORE='@(.|..)').

Quand exactement interdire .aussi était ajouté n'est pas toujours clair et varie avec chaque Unix. Quelques résultats ci-dessous.

BSD

L'interdiction de a .été ajoutée entre 2.9BSD (1983) et 2.10BSD (1987) et entre 4.2BSD (1983) et 4.3BSD (1986) (voir ce changement horodaté en 1985 dans le rapport unix-history-repo ).

$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.9BSD/root.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `..'
$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.10bsd.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `.' or `..'
rm: cannot remove `.' or `..'\n");

Pour dir/.et dir/.., voir ce changement en 1988 (BSD 4.3 Net / 1).

À ce jour, le rmrépertoire de FreeBSD (et de dérivés tels que macOS) vide toujours le répertoire actuel ou parent sur rm -rf ./ou rm -rf ../bien (compte pour rm -rf .*/).

Système V

Je n'ai pas beaucoup d'informations, car ni la source ni les fichiers binaires ne sont disponibles publiquement pour les dérivés Unix d'AT & T après la V7. Dans son manuel en ligne, HPUX (basé sur System III) mentionne toujours qu’il interdit uniquement, ..bien qu’il interdise effectivement les deux, ce qui est une indication selon laquelle au moins SysIII n’a pas interdit la suppression de .( edit : regardons maintenant rmle code source SysIII , pratiquement inchangé depuis Unix V7).

Tous les autres manuels en ligne que j'ai vérifiés mentionnent la suppression .ou l’ ..interdiction qui est censée être conforme à POSIX.

Solaris rmvide toujours le répertoire actuel ou parent sur rm -rf ./ou rm -rf ../.

GNOU

Le premier changelog de GNU fileutils contient toutes les informations historiques.

Bien qu’à l’origine, ni supprimer, .ni ..interdire, il ..était interdit en premier, puis les deux (y compris dir/.), tous entre 1990 et 1991.

autre

Comme nous l'avons vu, zshl'expansion de .*(ou de n'importe quel glob) n'inclut jamais .ou ..(même en shmode d'émulation). Le rmconstruit (que vous obtenez si vous zmodload zsh/files) ne traite donc pas .ou ..spécialement. Donc, avec cette fonction zshintégrée, vous pouvez rm -rf .ou rm -rf ..vider .ou .., mais rm -rf .*ne retirerez pas .ou ...

Dans busybox rm, l'interdiction de suppression de .et a ..été ajoutée à 0.52 (2001)

Stéphane Chazelas
la source
Bizarre, cela semble spécifier que rm -rf . /(notez l’espace) doit imprimer deux avertissements (pour .et /) et se terminer, mais il semble que nous ayons une question nous demandant comment nous en sortir tous les deux mois.
Kevin
6
@Kevin Tous les systèmes ne sont pas compatibles POSIX et la restriction du répertoire racine n'a été explicitement ajoutée que dans la dernière version de POSIX.
Juillet
@ Jlliagre je vois. GNU essaye généralement d’implémenter POSIX (+ extensions, bien sûr), et j’imagine qu’ils voudraient l’utiliser, mais si c’est assez nouveau, cela l’expliquerait.
Kevin
2
@ Stéphane: vous avez raison, mais j'ajouterais quand même un gros "Oui, cela pourrait arriver! Mais ..." au début de votre réponse, de sorte que les gens le sachent bien, en effet, sur certains (plus âgés ou non). Compatibles avec la norme -POSIX), ils pourraient supprimer les répertoires parents. J'essaie de toujours indiquer ces possibilités (c'est-à-dire que j'essaie de rester prudent, même si cela rend parfois la réponse plus difficile à lire / à mémoriser) ^^
Olivier Dulac
1
@ MartinSchröder, sur les BSD, il a été ajouté entre 2.8BSD et 2.10BSD (auparavant, seul ".." était interdit comme dans UnixV7) et entre 3BSD et 4.3RENO. Sur les systèmes SysV, c'est moins clair. Le manuel HPUX, par exemple, affirme qu'il interdit uniquement "..", mais interdit en fait les deux "." et "..", seul le manuel n'est pas à jour.
Stéphane Chazelas