'Rm. *' Já exclui o diretório pai?

53

A expressão .*é expandida pelo bash para incluir os diretórios atual e pai:

$ 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 .*
. ..

Se eu rodar rm -rf .*no meu Debian usando o GNU bash, version 4.2.36(1)-releasee rmde rm (GNU coreutils) 8.13, recebo esta mensagem:

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

Isso é coisa do GNU ou é POSIX? Existem sistemas * nix em que o comando acima será excluído silenciosamente .e ..?

Além disso, esse é um recurso de segurança do shell ou do rmpróprio comando?

terdon
fonte
4
Eu sei que esta questão está no contexto de rm, mas achei que valia a pena mencionar que você ainda pode ter resultados inesperados com chmod, chown, etc quando a correspondência .*.
Aaron Copley

Respostas:

59

A versão mais recente (a partir de 2017) da especificação POSIX para o rmutilitário está aqui (e a anterior ) e proíbe a exclusão de .e ...

Se um dos arquivos ponto ou ponto estiver especificado como a parte do nome de base de um operando (ou seja, o componente final do nome do caminho) ou se um operando for resolvido para o diretório raiz, a rm escreverá uma mensagem de diagnóstico para erro padrão e não fará nada mais com esses operandos.

Conforme observado por @jlliagre, a parte sobre /é uma adição ao SUSv4.

A mais antiga especificação do Unix disponível publicamente que eu pude encontrar ( XPF4 CAE rev2 (1994)), já especificou isso .e ..não pode ser removida, embora comentários no changelog do arquivo GNU sugeram que esse já era o caso nas especificações POSIX mais antigas.

Note-se que ela se aplica a dir/..e ../bem, mas algumas implementações (incluindo aqueles UNIX certificadas como Solaris 11 e MacOS) ainda não salvaguarda contra rm -rf ../ou rm -rf .*/).

história

Unices iniciais

A -ropção para rmfoi adicionada no Unix V3 (1973), embora excluindo apenas o conteúdo dos diretórios, você ainda precisará usar rmdirpara remover os diretórios.

Isso mudou no Unix V7 (1979, o lançamento que também introduziu o shell Bourne e do qual a maioria dos Unices deriva). rm -ragora removeu os diretórios também e não excluiu a ..árvore de diretórios. A página do manual declara:

É proibido remover o arquivo ..apenas para evitar as conseqüências anti-sociais de se fazer algo assim inadvertidamente rm -r .*.

(embora se possa argumentar que rm -r .*ainda é anti - social , pois exclui tudo porque .está incluído).

Ele ainda aceitou remover, .mas não desvinculou as entradas .ou ... Então, rm -r .era uma maneira eficaz de esvaziar o diretório atual.

Observe também que a salvaguarda era apenas para um ..argumento literal , não para dir/..ou ./... Portanto, rm -rf ./.*ainda removeria tudo no diretório pai recursivamente.

É interessante ver que isso já era para contornar o bug / falha de recurso pelo qual os globs poderiam incluir .e ..em sua expansão. Isso foi corrigido no shell Forsyth (a base do shell Minix original e do pdksh) no final dos anos 80, zsh(1990) e fish(2005), mas não em outros shells e, em particular, não na shlinguagem POSIX que requer a expansão de .*incluir .e ..se eles são retornados por readdir()( bashaborda o problema parcialmente apenas com shopt -s dotglobonde globs (exceto .xxxos) não incluem .ou .., e com ksh, você pode corrigi-lo fazendo isso FIGNORE='@(.|..)').

Quando exatamente proibir .também foi adicionado nem sempre é claro e varia de acordo com cada Unix. Algumas descobertas abaixo.

BSDs

A proibição de .foi adicionada em algum momento entre 2.9BSD (1983) e 2.10BSD (1987) e entre 4.2BSD (1983) e 4.3BSD (1986) (veja essa alteração com timestamp 1985 em 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");

Para dir/.e dir/..veja esta alteração em 1988 (BSD 4.3 Net / 1).

Até essa data, o rmFreeBSD (e derivados como o macOS) ainda esvazia o diretório atual ou pai sobre rm -rf ./ou rm -rf ../embora (é importante rm -rf .*/).

Sistema V

Não tenho muita informação, pois nem a fonte nem o binário estão disponíveis publicamente para os derivados da AT&T Unix após a V7. Em seu manual online, HPUX (com base no Sistema III) ainda menciona que apenas proíbe ..enquanto efetivamente proíbe tanto que é uma indicação de que, provavelmente, pelo menos SysIII não proibiu a exclusão de .( edição : Agora, olhando para o SysIII rmcódigo-fonte , é praticamente inalterado desde o Unix V7).

Todos os outros manuais on-line que verifiquei mencionam a exclusão .ou ..são proibidos, o que é esperado que seja compatível com POSIX.

O Solaris rmainda esvazia o diretório atual ou pai em rm -rf ./ou rm -rf ../.

GNU

O registro de alterações antecipado dos arquivos do GNU possui todas as informações históricas.

Embora originalmente não excluísse .ou ..fosse proibido, ..era proibido primeiro e depois ambos (inclusive dir/.), todos entre 1990 e 1991.

de outros

Como vimos, em zsh, a expansão de .*(ou qualquer glob) nunca inclui .ou ..(mesmo no shmodo de emulação). O rmbuiltin (que você obtém se você zmodload zsh/files), portanto, não trata .ou ..especialmente. Portanto, com esse zshbuiltin, você pode rm -rf .ou rm -rf ..esvaziar .ou .., mas rm -rf .*não removerá .ou ...

No busybox rm, a proibição de exclusão .e ..foi adicionada em 0,52 (2001)

Stéphane Chazelas
fonte
Estranho, isso parece especificar que rm -rf . /(observe o espaço) deve imprimir dois avisos (para .e /) e sair, mas parece que temos uma pergunta perguntando como se recuperar disso a cada dois meses.
Kevin
6
@ Kevin Nem todos os sistemas são compatíveis com POSIX e a restrição de diretório raiz foi explicitamente adicionada apenas na versão mais recente do POSIX.
Jlliagre
@ jlliagre eu vejo. O GNU geralmente tenta implementar o POSIX (extensões +, é claro), e eu imagino que eles gostariam de colocar este, mas se for relativamente novo, isso explicaria.
Kevin
2
@ Stephanie: você está certo, mas eu ainda acrescentaria um grande "Sim, isso poderia acontecer! Mas ..." no início de sua resposta, para que as pessoas, sem dúvida, saibam que, de fato, em alguns (mais velhos ou não) Compatíveis com o POSIX), eles poderiam excluir diretórios-pai. Eu tento sempre apontar aqueles possibilidade (ou seja, eu tento ficar no lado seguro, mesmo que faz a resposta, por vezes, difícil de ler / lembrar) ^^
Olivier Dulac
11
@ MartinSchröder, Nos BSDs, foi adicionado entre 2.8BSD e 2.10BSD (antes apenas ".." era proibido como no UnixV7) e entre 3BSD e 4.3RENO. Nos sistemas SysV, é menos claro. O manual HPUX, por exemplo, afirma que proíbe apenas "..", mas na verdade proíbe ambos "." e "..", é apenas o manual que não está atualizado.
Stéphane Chazelas