Por que o comando `find -type d -exec rmdir {} \;` produz "Esse arquivo ou mensagem de diretório não existe"

Por que o comando `find -type d -exec rmdir {} \;` produz "Esse arquivo ou mensagem de diretório não existe"

Para fins de teste, criei os seguintes diretórios.

user@linux:~$ mkdir dir0{1..3}

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir03
user@linux:~$ 

Então, eu removi comfind -exec

user@linux:~$ find -type d -exec rmdir {} \;
rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory
find: ‘./dir01’: No such file or directory
find: ‘./dir03’: No such file or directory
user@linux:~$ 

Os diretórios foram removidos, eu verifiquei.

user@linux:~$ ls -l
total 0
user@linux:~$ 

Minhas perguntas são:

1) Não entendo por que as mensagens estavam lá. Alguma ideia do porquê?

rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory

Não vejo esse tipo de erro comrmdir

user@linux:~$ mkdir dir0{1..3}
user@linux:~$ 

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir03
user@linux:~$ 

user@linux:~$ rmdir *
user@linux:~$ 

user@linux:~$ ls -l
total 0
user@linux:~$ 

2) É possível remover essas mensagens?

Responder1

Você recebe os erros "Esse arquivo ou diretório não existe" findporque findestá tentando entrar nos diretórios que acabou de remover. Por padrão, ele aplicará suas ações a todos os itens correspondentes no diretório que está visitando antes de continuar nos subdiretórios.

Adicione -depthà invocação de findto make finduma pesquisa profunda em seus caminhos de pesquisa, o que por sua vez significa que se você executar rmdirem um diretório, ele já o terá visitado e não tentará visitá-lo novamente.

A -depthopção está implícita ao usar -deletepor esse motivo (em implementações finddisso -delete).

find . -depth -type d -exec rmdir {} \;

-depthé uma opção padrão para o findutilitário.

Observe que rmdirsó funciona em diretórios vazios. Se você tiver muitos diretórios não vazios, o comando acima produziria muitas mensagens de erro.

Em vez disso, se você findsuportar, use -empty:

find . -type d -empty -delete

Isso excluiria diretórios vazios.

Com um findque não possui o não padrão -deletenem -emtpy:

find . -depth -type d -exec sh -c '
    for dirpath do
        set -- "$dirpath"/*
        [ ! -e "$1" ] && rmdir "$dirpath"
    done' sh {} +

Isso testaria se os diretórios encontrados estavam vazios e, se estivessem, seriam excluídos.

Esse é um longo trecho de código para evitar ver algumas mensagens de erro devido ao fato de os diretórios não estarem vazios, mas quaisquer mensagens de erro quesãoesperamos que sejam mais interessantes de se ver, pois provavelmente seriam erros de "permissão negada". Redirecionar os erros para /dev/nullo primeiro findcomando na parte superior teria ocultado tais erros.

Responder2

O que presumivelmente acontece é que, com a -exec ... \;construção, find faz seu trabalho passo a passo:

  • percorrer a árvore de diretórios, encontrando entradas que correspondam -type de
  • execute rmdiressas entradas assim que forem encontradas.

Isso significa que, no seu exemplo, find irá olhar para dir01, mantê-lo em mente como um diretório para entrar mais tarde, depois executá rmdir-lo e, então, ao tentar recorrer a dir01, falhará porque ele não existe mais.

Executar with -exec rmdir {} +deve ajudar neste caso: uma única chamada rmdir dir01 dir02 dir03será emitida. Isso elimina as últimas três mensagens de erro.

A mensagem de erro .é porque, bem ., o diretório atual é de fato um diretório, mas não um que rmdirpode ser excluído, porque não está vazio. Use -min-depthpara parar de considerá-lo, fazendo o comando:

find -mindepth 1 -type d -exec rmdir {} +

Isto não é perfeito; diretórios aninhados ou um grande número de diretórios correspondentes ainda podem causar a impressão de mensagens de erro, mas isso deve funcionar no caso simples da pergunta.

informação relacionada