¿'Rm. *' Alguna vez elimina el directorio padre?

53

.*Bash expande la expresión para incluir los directorios actual y principal:

$ 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 ejecuto rm -rf .*mi Debian usando GNU bash, version 4.2.36(1)-releasey rmde rm (GNU coreutils) 8.13, recibo este mensaje:

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

¿Es esto una cosa de GNU o es POSIX? ¿Hay algún sistema * nix donde el comando anterior se eliminará silenciosamente .y ..?

Además, ¿es esta una característica de seguridad del shell o del rmcomando en sí?

terdon
fuente
44
Sé que esta pregunta es en el contexto de rm, pero pensé que valía la pena mencionar que aún puede tener resultados inesperados con chmod, chown, etc. cuando juego .*.
Aaron Copley

Respuestas:

59

La última versión (a partir de 2017) de la especificación POSIX para la rmutilidad está aquí (y la anterior allí ) y prohíbe la eliminación de .y ...

Si cualquiera de los archivos dot o dot-dot se especifican como la porción de nombre base de un operando (es decir, el componente final del nombre de ruta) o si un operando se resuelve en el directorio raíz, rm escribirá un mensaje de diagnóstico de error estándar y no hará nada más con tales operandos.

Como señaló @jlliagre, la parte sobre /es una adición en SUSv4.

La especificación de Unix más antigua disponible públicamente que pude encontrar ( XPF4 CAE rev2 (1994)), ya especificó eso .y ..no se puede eliminar, aunque los comentarios en el registro de cambios de archivos de GNU sugieren que ya era el caso en las especificaciones POSIX más antiguas.

Tenga en cuenta que se aplica a dir/..y ../, así, pero algunas implementaciones (incluyendo certificados por los UNIX como Solaris 11 y MacOS) todavía no salvaguarda contra rm -rf ../o rm -rf .*/).

historia

Unices tempranos

La -ropción de rmse agregó en Unix V3 (1973) aunque solo estaba eliminando el contenido de los directorios, aún necesitaría usar rmdirpara eliminar directorios.

Eso cambió en Unix V7 (1979, el lanzamiento que también introdujo el shell Bourne y del que deriva la mayoría de los Unices). rm -rahora también eliminó directorios y no eliminaría el ..árbol de directorios. La página del manual dice:

Está prohibido eliminar el archivo ..simplemente para evitar las consecuencias antisociales de hacer algo así sin darse cuenta rm -r .*.

(aunque se podría argumentar que rm -r .*todavía es antisocial ya que elimina todo porque .está incluido).

Todavía aceptó eliminar .aunque no desvincularía las entradas .o ... Entonces, rm -r .fue una forma efectiva de vaciar el directorio actual.

También tenga en cuenta que la protección fue solo para un ..argumento literal , no para dir/..o ./... Entonces, rm -rf ./.*aún eliminaría todo en el directorio padre de forma recursiva.

Es interesante ver que eso ya era para solucionar el error / mal funcionamiento por el cual los globos podrían incluir .y ..en su expansión. Eso se arregló en el shell Forsyth (la base del shell Minix original y pdksh) a finales de los años 80, zsh(1990) y fish(2005) pero no en otros shells y, en particular, no en el shlenguaje POSIX que requiere la expansión de .*incluir .y ..si son devueltos por readdir()( bashaborda el problema en parte solo con shopt -s dotglobdónde los globos (excepto .xxxlos) no incluyen .o .., y con ksh, puede solucionarlo haciendo FIGNORE='@(.|..)').

Cuando .también se agregó exactamente la prohibición no siempre es claro y varía con cada Unix. Algunos hallazgos a continuación.

BSD

La prohibición de .se agregó en algún momento entre 2.9BSD (1983) y 2.10BSD (1987) y entre 4.2BSD (1983) y 4.3BSD (1986) (ver este cambio marcado en 1985 en el repositorio de historia de Unix ).

$ 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");

Para dir/.y dir/.., vea este cambio en 1988 (BSD 4.3 Neto / 1).

Hasta la fecha, la rmversión de FreeBSD (y derivados como macOS) todavía vacía el directorio actual o principal en rm -rf ./o rm -rf ../aunque (es importante rm -rf .*/).

Sistema V

No tengo mucha información ya que ni la fuente ni el binario están disponibles públicamente para los derivados de AT&T Unix después de V7. En su manual en línea, HPUX (basado en el Sistema III) todavía menciona que solo prohíbe ..mientras efectivamente prohíbe ambos, lo cual es una indicación de que probablemente al menos SysIII no prohibió la eliminación de .( editar : ahora mirando el rmcódigo fuente SysIII , es prácticamente sin cambios desde Unix V7).

Todos los demás manuales en línea que he revisado mencionan la eliminación .o ..está prohibido, lo que se espera que sea compatible con POSIX.

Solaris rmtodavía vacía el directorio actual o principal en rm -rf ./o rm -rf ../.

ÑU

El registro de cambios temprano para los archivos GNU contiene toda la información histórica.

Si bien originalmente no se eliminó .ni ..se prohibió, ..se prohibió primero y luego ambos (incluido dir/.), todo entre 1990 y 1991.

otro

Como vimos, en zsh, la expansión de .*(o cualquier globo) nunca incluye .o ..(incluso en shmodo de emulación). El rmincorporado (que obtienes si lo haces zmodload zsh/files), por lo tanto, no se trata .o ..especialmente. Entonces, con ese zshincorporado, puede rm -rf .o rm -rf ..vaciar .o .., pero rm -rf .*no eliminará .o ...

En busybox rm, la prohibición de eliminación de .y ..se agregó en 0.52 (2001)

Stéphane Chazelas
fuente
Extraño, eso parece especificar que rm -rf . /(tenga en cuenta el espacio) debe imprimir dos advertencias (para .y /) y salir, pero parece que recibimos una pregunta sobre cómo recuperarse de eso cada dos meses.
Kevin
66
@Kevin No todos los sistemas son compatibles con POSIX y la restricción del directorio raíz solo se agregó explícitamente en la última versión de POSIX.
jlliagre
@jlliagre ya veo. GNU generalmente trata de implementar POSIX (+ extensiones, por supuesto), y me imagino que querrían ponerlo, pero si es bastante nuevo eso lo explicaría.
Kevin
2
@Stephane: tienes razón, pero aún así agregaría un gran "Sí, ¡podría suceder! Pero ..." al comienzo de tu respuesta, para que las personas sin duda lo sepan en algunos (mayores o simplemente no Sistemas compatibles con POSIX), podrían eliminar directorios principales. Intento señalar siempre esa posibilidad (es decir, trato de mantenerme seguro, incluso si la respuesta a veces es más difícil de leer / recordar) ^^
Olivier Dulac
1
@ MartinSchröder, en BSD, se agregó en algún lugar entre 2.8BSD y 2.10BSD (antes solo ".." estaba prohibido como en UnixV7) y entre 3BSD y 4.3RENO. En los sistemas SysV, es menos claro. El manual de HPUX, por ejemplo, afirma que solo prohíbe ".." pero en efecto prohíbe ambos "." y "..", es solo el manual que no está actualizado.
Stéphane Chazelas