Der Ausdruck .*
wird von bash erweitert, um das aktuelle und das übergeordnete Verzeichnis einzuschließen:
$ 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 .*
. ..
Wenn ich rm -rf .*
ausführe auf meinem Debian mit GNU bash, version 4.2.36(1)-release
und rm
von rm (GNU coreutils) 8.13
, erhalte ich diese Meldung:
$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'
Ist das eine GNU-Sache oder ist es POSIX? Gibt es *nix-Systeme, bei denen der obige Befehl .
stillschweigend löscht und ..
?
Außerdem ist dies ein Sicherheitsfeature der Shell oder des rm
Befehl selbst?
Akzeptierte Antwort:
Die neueste (Stand 2017) Version der POSIX-Spezifikation für den rm
Dienstprogramm ist hier (und das vorherige dort) und verbietet das Löschen von .
und ..
.
Wenn eine der Dateien Punkt oder Punkt-Punkt als Basisnamensteil eines Operanden (d. h. die letzte Pfadnamenskomponente) angegeben wird oder wenn ein Operand in das Stammverzeichnis aufgelöst wird, soll rm eine Diagnosenachricht in den Standardfehler schreiben und nichts tun mehr mit solchen Operanden.
Wie von @jlliagre bemerkt, der Teil über /
ist eine Ergänzung in SUSv4.
Die älteste öffentlich verfügbare Unix-Spezifikation, die ich finden konnte (XPF4 CAE rev2 (1994)), spezifizierte bereits diesen .
und ..
kann nicht entfernt werden, obwohl Kommentare im Änderungsprotokoll von GNU fileutils darauf hindeuten, dass dies bereits in älteren POSIX-Spezifikationen der Fall war.
Beachten Sie, dass dies für dir/..
gilt und ../
auch, aber einige Implementierungen (einschließlich UNIX-zertifizierter wie Solaris 11 und macOS) schützen immer noch nicht vor rm -rf ../
oder rm -rf .*/
).
Geschichte
Frühe Einsiedler
Das -r
Option zu rm
wurde in Unix V3 (1973) hinzugefügt, obwohl es nur den Inhalt der Verzeichnisse löschte, müssten Sie immer noch rmdir
verwenden um Verzeichnisse zu entfernen.
Das änderte sich in Unix V7 (1979, die Version, die auch die Bourne-Shell einführte und von der die meisten Unices abstammen). rm -r
entfernte jetzt auch Verzeichnisse und würde ..
nicht löschen Verzeichnisbaum. In der Manpage heißt es:
Es ist verboten, die Datei ..
zu entfernen lediglich um die unsozialen Folgen zu vermeiden, wenn Sie versehentlich etwas wie rm -r .*
tun .
(obwohl man argumentieren könnte, dass rm -r .*
ist immer noch asozial da es alles löscht, weil .
ist enthalten).
Es hat immer noch akzeptiert, .
zu entfernen obwohl es die Verknüpfung .
nicht aufheben würde oder ..
Einträge. Also dann rm -r .
war ein effektiver Weg, um das aktuelle Verzeichnis zu leeren.
Beachten Sie auch, dass der Schutz nur für wörtliche ..
galt Argument, nicht für dir/..
oder ./..
. Also rm -rf ./.*
würde immer noch alles im übergeordneten Verzeichnis rekursiv entfernen.
Es ist interessant zu sehen, dass dies bereits dazu diente, den Fehler/die Fehlfunktion zu umgehen, durch die Globs .
enthalten konnten und ..
in ihrer Ausdehnung. Das wurde Ende der 80er in der Forsyth-Shell (der Basis für die ursprüngliche Minix-Shell und pdksh) behoben, zsh
(1990) und fish
(2005), aber keine anderen Shells und insbesondere nicht die POSIX sh
Sprache, die die Erweiterung von .*
erfordert um .
einzuschließen und ..
wenn sie von readdir()
zurückgegeben werden (bash
behebt das Problem teilweise nur mit shopt -s dotglob
wobei Globs (außer .xxx
Einsen) enthalten nicht .
oder ..
, und mit ksh
, können Sie es beheben, indem Sie FIGNORE='@(.|..)'
ausführen ).
Beim genauen Verbot von .
was hinzugefügt wurde, ist nicht immer klar und variiert mit jedem Unix. Nachfolgend einige Ergebnisse.
BSDs
Das Verbot von .
wurde irgendwann zwischen 2.9BSD (1983) und 2.10BSD (1987) und zwischen 4.2BSD (1983) und 4.3BSD (1986) hinzugefügt (siehe diese Änderung mit dem Zeitstempel 1985 im 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");
Für dir/.
und dir/..
, siehe diese Änderung von 1988 (BSD 4.3 Net/1).
Bis heute ist die rm
von FreeBSD (und Derivaten wie macOS) leert immer noch das aktuelle oder übergeordnete Verzeichnis auf rm -rf ./
oder rm -rf ../
obwohl (wichtig für rm -rf .*/
).
System V
Ich habe nicht viele Informationen, da weder Quelle noch Binärdatei für die AT&T-Unix-Derivate nach V7 öffentlich verfügbar sind. HPUX (basierend auf System III) erwähnt in seinem Online-Handbuch noch, dass es nur ..
verbietet während es effektiv beides verbietet, was ein Hinweis darauf ist, dass wahrscheinlich zumindest SysIII das Löschen von .
nicht verboten hat (bearbeiten :Betrachten wir nun den SysIII rm
Quellcode, er ist seit Unix V7 praktisch unverändert).
Alle anderen Online-Handbücher, die ich überprüft habe, erwähnen das Löschen von .
oder ..
ist verboten, von denen zu erwarten ist, dass sie POSIX-konform sind.
Solaris rm
leert weiterhin das aktuelle oder übergeordnete Verzeichnis bei rm -rf ./
oder rm -rf ../
.
GNU
Das frühe Änderungsprotokoll für die GNU-Dateidienstprogramme enthält alle historischen Informationen.
Während ursprünglich weder .
gelöscht wurde oder ..
waren verboten, ..
wurde zuerst verboten und dann beide (einschließlich dir/.
), alle zwischen 1990 und 1991.
Sonstiges
Wie wir gesehen haben, in zsh
, die Erweiterung von .*
(oder irgendein Glob) enthält niemals .
oder ..
(sogar in sh
Emulationsmodus). Der rm
builtin (das Sie erhalten, wenn Sie zmodload zsh/files
) behandelt daher .
nicht oder ..
speziell. Also, mit diesem zsh
eingebaut, können Sie rm -rf .
oder rm -rf ..
um .
zu leeren oder ..
, aber rm -rf .*
wird .
nicht entfernen oder ..
.
In busybox rm
, das Verbot der Löschung von .
und ..
wurde in 0.52 (2001) hinzugefügt