Provavelmente porque remover o diretório de trabalho atual não seria uma boa ideia.
Alexej Magura
Concordo - eu gosto do comportamento padrão, mas não é consistente com, por exemplo find . -print,.
mbroshi
@AlexejMagura, embora eu simpatize, não vejo por que remover o diretório atual deve ser diferente de remover um arquivo aberto. O objeto permanecerá vivo até que exista uma referência a ele e, em seguida, o lixo será coletado posteriormente. Você pode fazer cd ..; rm -r dircom outro shell com semântica bastante clara ...
Rmano
@Rmano isso é verdade: é apenas algo que eu não faria por princípio: basta subir um diretório e excluir o diretório atual. Não sei ao certo por que isso é tão importante - embora eu tenha tido alguns infortúnios com o diretório atual que não existe mais, como caminhos relativos que não estão mais funcionando, mas você sempre pode sair usando um caminho absoluto - mas uma parte de mim apenas diz que não é uma boa ideia em geral.
Alexej Magura
Respostas:
29
Os membros findutilscientes disso , são compatíveis com * BSD:
Um dos motivos pelos quais ignoramos a exclusão de "." é para compatibilidade com * BSD, onde essa ação se originou.
O NEWS no código fonte findutils mostra que eles decidiram manter o comportamento:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[ATUALIZAR]
Como essa questão se tornou um dos tópicos mais importantes, então eu mergulhei no código-fonte do FreeBSD e saí por uma razão mais convincente.
Porque seu findcomando retorna .como resultado. Na página de informações de rm:
Qualquer tentativa de remover um arquivo cujo último componente de nome de arquivo seja '.' ou '..' é rejeitado sem aviso, conforme exigido pelo POSIX.
Portanto, parece findapenas seguir as regras do POSIX neste caso.
Como deveria: POSIX é o rei, além de remover o diretório atual pode causar problemas muito grandes, dependendo do aplicativo pai e do que não. Como se o diretório atual estivesse /var/loge você o executasse como root, pensando que ele removeria todos os subdiretórios e também o diretório atual?
Alexej Magura
1
Essa é uma boa teoria, mas a manpágina para finddiz: "Se a remoção falhar, uma mensagem de erro será emitida". Por que nenhum erro é impresso?
mbroshi
1
@AlexejMagura Removendo o diretório atual fina funciona em geral: mkdir foo && cd foo && rmdir $(pwd). Está removendo .(ou ..) que não funciona.
O significado de excluir nome do caminho / ponto não é claro, porque o nome do arquivo (diretório) no diretório pai a ser removido não é claro, principalmente na presença de vários links para um diretório.
Enquanto 林果 皞 e Thomas já deram boas respostas sobre isso, sinto que suas respostas se esqueceram de explicar por que esse comportamento foi implementado em primeiro lugar.
No seu find . -deleteexemplo, excluir o diretório atual parece bastante lógico e sensato. Mas considere:
$ find . -name marti\*
./martin
./martin.jpg
[..]
A exclusão .ainda parece lógica e sã para você?
Excluir um diretório não vazio é um erro - portanto, é improvável que você perca dados com isso find(embora possa com rm -r) -, mas seu shell terá seu diretório de trabalho atual definido em um diretório que não existe mais, causando confusão. e comportamento surpreendente:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
Não excluir o diretório atual é simplesmente um bom design de interface e está em conformidade com o princípio da menor surpresa.
find . -print
,.cd ..; rm -r dir
com outro shell com semântica bastante clara ...Respostas:
Os membros
findutils
cientes disso , são compatíveis com * BSD:O NEWS no código fonte findutils mostra que eles decidiram manter o comportamento:
[ATUALIZAR]
Como essa questão se tornou um dos tópicos mais importantes, então eu mergulhei no código-fonte do FreeBSD e saí por uma razão mais convincente.
Vamos ver o código fonte do utilitário find do FreeBSD :
Como você pode ver, se não filtrar pontos e pontos, alcançará a
rmdir()
função C definida pelos POSIX'sunistd.h
.Faça um teste simples, rmdir com o argumento ponto / ponto-ponto retornará -1:
Vamos dar uma olhada em como o POSIX descreve o rmdir :
Nenhuma razão foi dada por quê
shall fail
.Eu encontrei
rename
explicar alguns reaso n:Caminhos cíclicos do sistema de arquivos ?
Eu olho sobre a linguagem de programação C (2nd Edition) e procuro o tópico do diretório, surpreendentemente, achei o código semelhante :
E o comentário!
"loop para sempre" , é o mesmo que
rename
descrever como "caminhos do sistema de arquivos cíclicos" acima.Modifico levemente o código e o faço executar no Kali Linux com base nesta resposta :
Vamos ver:
Funciona corretamente, e agora se eu comentar a
continue
instrução:Como você pode ver, eu tenho que usar Ctrl+ Cpara matar esse programa de loop infinito.
O diretório '..' lê sua primeira entrada '..' e faz um loop para sempre.
Conclusão:
O GNU
findutils
tenta compatível com ofind
utilitário no * BSD .find
O utilitário * BSD utiliza internamente armdir
função C compatível com POSIX que ponto / ponto-ponto não é permitido.O motivo de
rmdir
não permitir ponto / ponto é impedir caminhos cíclicos do sistema de arquivos.A linguagem de programação C, escrita por K&R, mostra o exemplo de como ponto / ponto-ponto levará ao programa de loop para sempre.
fonte
Porque seu
find
comando retorna.
como resultado. Na página de informações derm
:Portanto, parece
find
apenas seguir as regras do POSIX neste caso.fonte
/var/log
e você o executasse como root, pensando que ele removeria todos os subdiretórios e também o diretório atual?man
página parafind
diz: "Se a remoção falhar, uma mensagem de erro será emitida". Por que nenhum erro é impresso?mkdir foo && cd foo && rmdir $(pwd)
. Está removendo.
(ou..
) que não funciona.A chamada do sistema rmdir falha com EINVAL se o último componente do caminho do argumento for
"."
. Está documentado em http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html e a justificativa para o comportamento é:fonte
Ligar
rmdir(".")
como uma chamada do sistema não funcionou quando tentei, portanto, nenhuma ferramenta de nível superior pode ser bem-sucedida.Você deve excluir o diretório pelo nome real e não pelo
.
alias.fonte
Enquanto 林果 皞 e Thomas já deram boas respostas sobre isso, sinto que suas respostas se esqueceram de explicar por que esse comportamento foi implementado em primeiro lugar.
No seu
find . -delete
exemplo, excluir o diretório atual parece bastante lógico e sensato. Mas considere:A exclusão
.
ainda parece lógica e sã para você?Excluir um diretório não vazio é um erro - portanto, é improvável que você perca dados com isso
find
(embora possa comrm -r
) -, mas seu shell terá seu diretório de trabalho atual definido em um diretório que não existe mais, causando confusão. e comportamento surpreendente:Não excluir o diretório atual é simplesmente um bom design de interface e está em conformidade com o princípio da menor surpresa.
fonte