Exclua subpastas vazias, mantenha a pasta pai

15

Quando eu uso

find /home/user/parentdir -type d -empty -delete

procura recursivamente por subpastas vazias dentro /home/user/parentdire as exclui. Mas se /home/user/parentdirtambém estiver vazio, também excluirá a parentdirpasta, o que é indesejável para mim.

Quero manter isso parentdirem rsyncalguns arquivos para backup ou nuvem. Após o processamento, preciso excluir as pastas vazias, mas parece improdutivo recriar parentdirtodas as vezes.

Alguma sugestão para manter parentdir? Pensei em criar um .nocopyarquivo dentro dele e excluí-lo rsync, mas parece exagero. Existe uma maneira mais elegante?

TNT
fonte
se você adicionar uma barra / ao final de / parentdir (isto é / parentdir /), isso faz alguma diferença?
Graham
6
-mindepth 1?
steeldriver 15/09/19
@Graham / parentdir / exclui parentdir também, então não faz diferença.
TNT
ah, vejo que perdi o * no final que @Amourk menciona em sua resposta.
Graham

Respostas:

25

Simplesmente faça find /home/user/parentdir -mindepth 1 -type d -empty -delete.

Veja:

$ mkdir -p test1/test2
$ find test1 -type d
test1
test1/test2
$ find test1 -mindepth 1  -type d
test1/test2

A find /home/user/parentdir/* resposta do AmourK é indesejável quando há muitos arquivos e é complicada demais.

chx
fonte
15

Ao adicionar /*no final de parentdir, você está executando a ação em todos os subdiretórios do parentdir, e não em parentdirsi mesmo. E assim, da mesma forma, /home/user/não é excluído no comando antigo, parentdirnão será excluído no comando abaixo. *é chamado de operador glob e corresponde a qualquer sequência de caracteres.

find /home/user/parentdir/* -type d -empty -delete

AmourK
fonte
7
Uma coisa a ter em mente com essa abordagem é que, se houver um grande número de arquivos /home/user/parentdir/, a glob expandida poderá exceder ARG_MAX, resultando em um erro muito longo da lista de argumentos . Você pode reduzir a chance disso acontecer alterando o glob para */que ele corresponda apenas aos diretórios.
Steeldriver # 15/19
12
Lembre-se também de que isso não encontrará crianças começando com um ponto. E um dia você perceberá isso e, se também encontrar um ". *", Estará em um mundo enorme de mágoa (porque ". *" Corresponde a ".."). Me pergunte como eu sei.
Glenn Willen
11
@ GlennWillen, por que acho que deveríamos estar sentados em um bar com bebidas à nossa frente antes de pedir que você conte essa história?
Monty Harder
@MontyHarder Felizmente não foi tão ruim quanto poderia ter sido. Foi no meu primeiro sistema Unix, que era uma máquina Solaris pertencente à minha escola. Graças a Deus eu não estava executando 'rm', mas sim 'chown'. Eu estava usando o root para tentar corrigir a propriedade de tudo no meu diretório pessoal. Em vez disso, assumi a propriedade de TODOS os diretórios pessoais (e todo o seu conteúdo) e depois tive que devolvê-los.
Glenn Willen
Tive um colega de trabalho treinando um novo funcionário sobre como instalar um software. Isso envolvia a /tmpcriação de um subdiretório, a descompactação de um pacote compactado com gzip, a execução do instalador e a limpeza. O novato pensou que rm -rf /tmp/foo-installera o caminho certo para fazer isso, e como a mão experiente dizia "Nããããão" em sua melhor impressão de Darth-Vader no final do Episódio III, o novato descobriu da maneira mais difícil o quão perto / e as teclas Enter estavam entre si. Tivemos que inicializar a partir do disco de restauração do software de backup e recarregar todo o servidor da fita.
precisa saber é o seguinte
0

se você possui o php-cli instalado,

printf %s $(pwd) | php -r 'function f(string $dir){var_dump($dir);$dir.=DIRECTORY_SEPARATOR;foreach(glob("$dir*",GLOB_ONLYDIR) as $d){f($d);}global $original;if(substr($dir,0,-strlen(DIRECTORY_SEPARATOR))!==$original && empty(glob("$dir*"))){rmdir($dir);}}f(($original=stream_get_contents(STDIN)));'
hanshenrik
fonte
você queria foreach (RecursiveIteratorIterator(RecursiveDirectoryIterator($dir)) as $p) if (empty($skipped)) $skipped = TRUE; elseif ($p->isDir()) @rmdir($p->getPathname());ou algo parecido com isso. $skippedcuida de pular o primeiro, @rmdirtenta remover um dir e silenciosamente (esse é o @) falha se não estiver vazio.
chx 16/09/19
0

Quando você precisa apenas de um nível (deixando uma pasta pai, mas excluindo pastas filho vazias), um truque fácil é usar rmdir.

rmdir parent/*

Exclui todas as subpastas vazias, mas imprime apenas um erro para arquivos e pastas não vazias.

Isso não funciona recursivamente, mas ao conhecer a estrutura da pasta, pode ser a maneira mais rápida de fazer algo como

rmdir parent/*/*/* # deletes parent/a/b/c when empty
rmdir parent/*/* # deletes parent/a/b when it is now empty
rmdir parent/* # deletes parent/a when it is now empty

Vantagem: Fácil de lembrar, rápido para digitar, pouco potencial para escolher um parâmetro errado.
Desvantagem: menos flexível, possivelmente várias mensagens de erro no seu terminal.

todos
fonte