Encontrando diretórios vazios UNIX

90

Preciso encontrar diretórios vazios para uma determinada lista de diretórios. Alguns diretórios possuem diretórios dentro dele.

Se os diretórios internos também estiverem vazios, posso dizer que o diretório principal está vazio, caso contrário, não está vazio.

Como posso testar isso?

Por exemplo:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty
soField
fonte
2
Acho que a resposta de Martin é a mais apropriada aqui. A resposta aceita atualmente é apenas um pseudocódigo incompleto.
Léo Léopold Hertz 준영

Respostas:

34

Verifique se find <dir> -type fproduz alguma coisa. Aqui está um exemplo:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Marcelo Cantos
fonte
2
Não, não produzirá subdiretórios. É para isso que -type fserve.
Marcelo Cantos
Porém, se houver arquivos vazios , sua solução não produzirá a mensagem.
Yasir Arsanukaev
3
Yasir: Eu acho que um diretório contendo um arquivo vazio não está vazio. Não seria esse o resultado correto?
Ukko
2
@akostadinov: Se eu criar os diretórios e arquivos conforme indicado pelo OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- e executar o código em minha resposta, ele informa que B e C estão vazios, conforme exigido pelo OP. Portanto, você precisará ser um pouco mais específico do que "não vai funcionar".
Marcelo Cantos
1
Se você for um noob do Bash como eu, verifique o que -z significa aqui .
OmarOthman
255

Depende um pouco do que você deseja fazer com os diretórios vazios. Eu uso o comando abaixo quando desejo excluir todos os diretórios vazios dentro de uma árvore, digamos testdiretório.

find test -depth -empty -delete

Uma coisa a notar sobre o comando acima é que ele também removerá arquivos vazios , então use a opção -type d para evitar isso.

find test -depth -type d -empty -delete

Solte -deletepara ver os arquivos e diretórios correspondentes.

Se a sua definição de árvore de diretório vazia é que ela não contém arquivos, então você será capaz de juntar algo baseado em se find test -type fretorna algo.

find é um ótimo utilitário, e RTFM cedo e frequentemente para realmente entender o quanto ele pode fazer :-)

Martin
fonte
8
-delete implica em -depth (pelo menos para GNU findutils 4.4.2)
Dr. Pessoa Pessoa II
4
não sabia -empty, tão conveniente!
Raffi
2
Porém em máquinas que não são as mais recentes e melhores do Linux. (EG Solaris), então você não tem recursos para encontrar fantasia como -empty ou -delete.
anthony
3
No MacOS-X, para diretórios quase vazios, execute find test -name ".DS_Store" -deleteprimeiro e, em seguida, o -empty deletecomando. Observe também, como para pushdo diretório pai, de modo que find testse torna find ., mas o resto dos comandos são os mesmos.
Olie
1
@Martin Você pode adicionar a definição de -depthaqui, ou seja, Causa encontrar para realizar uma travessia em profundidade, ou seja, os diretórios são visitados em pós-ordem e todas as entradas em um diretório atuarão antes do próprio diretório. Eu acho que é relevante aqui.
Léo Léopold Hertz 준영
48

Você pode usar o seguinte comando:

find . -type d -empty
mosg
fonte
1
-empty só funciona se o diretório atual estiver completamente vazio, não se a subárvore não contiver arquivos.
Marcelo Cantos
@soField Testado find. -tipo d -empty com FreeBSD e CentOS. Funciona bem. Qual é o seu sistema operacional?
mosg
1
hp-ux, portanto, não há parâmetro vazio
soField
@soField Então, veja, é melhor (para todos nós) postar esses dados no topo da sua pergunta ...
mosg
2
find também não tem -empty no solaris, mas tem -depth para forçar a travessia em profundidade, para que subdiretórios vazios possam ser excluídos antes que o diretório pai seja verificado quanto a vazio.
eirikma
26
find directory -mindepth 1 -type d -empty -delete

Esta é a versão que achei mais interessante. Se executado a partir do diretório interno , ele excluirá todos os diretórios vazios abaixo (um diretório é considerado vazio se contiver apenas diretórios vazios).

A opção mindepth impede que o próprio diretório seja excluído se estiver vazio.

Dr. Pessoa Pessoa II
fonte
2
Você também pode fazer isso rmdir --ignore-fail-on-non-empty -p directorypara se livrar dos pais.
Pete Peterson
@Pete Peterson Meu comando parece remover diretórios que contêm apenas outros diretórios vazios (que é o que OP também parece querer). Noto que o seu comando normalmente deixará o usuário em um diretório com um nó-i ausente, mesmo se eles realizarem o que desejam, o que pode ser confuso para eles. Talvez eu esteja perdendo o ponto.
Dr. Pessoa Pessoa II
23

find . -type d -empty

encontra e lista diretórios e subdiretórios vazios na árvore atual. Por exemplo, lista resultante de diretórios e subdiretórios vazios:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

Nenhuma operação é feita nos diretórios. Eles são simplesmente listados. Isso funciona para mim.

user7194913
fonte
16

Apenas encontre diretórios vazios

Para encontrar apenas diretórios vazios (conforme especificado no título da pergunta), a resposta do mosg está correta:

find -type d -empty

Mas -emptypode não estar disponível em findversões muito antigas (é o caso do HP-UX, por exemplo). Se este for o seu caso, consulte as técnicas descritas na seção a seguir Um diretório está vazio? .

Excluir diretórios vazios

Isso é um pouco complicado: suponha que um diretório MyDircontenha diretórios vazios. Depois de remover esses diretórios vazios, MyDirele se tornará um diretório vazio e também deve ser removido. Portanto, eu uso o comando rmdircom a opção --parents(ou -p) que também remove os diretórios pais quando possível:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

Na findversão mais antiga, a instrução +ainda não é compatível, portanto, você pode usar em seu ;lugar:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

O diretório está vazio?

A maioria dessas respostas explica como verificar se um diretório está vazio. Portanto, apresento aqui as três técnicas diferentes que conheço:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi

    uma variação:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi

    Explicação:

    • find -pruneé semelhante a find -maxdepth 0usar menos caracteres
    • find -type d imprime diretórios apenas
    • find -empty imprime os diretórios e arquivos vazios

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
  2. (( ${#files} ))

    Este truque é 100%, bashmas invoca (gera) um sub-shell. A ideia é de Bruno De Fraine e melhorada pelo comentário do teambob . Eu aconselho este se você usar e se seu script não precisa ser portátil.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi

    Observação: não há diferença entre um diretório vazio e um não existente (e mesmo quando o caminho fornecido é um arquivo).

  3. [ $(ls -A your/dir) ]

    Este truque foi inspirado no artigo da nixCraft postado em 2007. Andrew Taylor respondeu em 2008 e gr8can8dian em 2011.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi

    ou a versão de bashismo de uma linha:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."

    Nota: ls retorna $?=2quando o diretório não existe. Mas não há diferença entre um arquivo e um diretório vazio.

Olibre
fonte
rmdir -vpme ajudou imensamente, já que eu precisava não apenas excluir todos os diretórios vazios em uma raiz, mas verificar se há diretórios vazios e diretórios pai após excluir um arquivo. Na minha situação, diretórios vazios funcionam, desde que não estejam na árvore da qual estou removendo um arquivo. Obrigado!
Ethan Hohensee
2

Esta função recursiva parece fazer o truque:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Dada esta estrutura de diretório de exemplo:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- arquivo 5
    | - dir4 /
    | | - dirD /
    | `- arquivo4
    `- dir5 /
        `- dirE /
            `- dir_V /

O resultado da execução dessa função seria:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

que falta /dir4/dirD. Se você mover a chamada recursiva findempty "$dir"após o fi, a função incluirá esse diretório em seus resultados.

Pausado até novo aviso.
fonte
2

Que tal rmdir *? Esse comando falhará em diretórios não vazios.

Evandrix
fonte
Algo que tenho feito às vezes, para limpeza geral. Também fez coisas como rmdir */*/* */* * Embora que não lida com 'arquivos de ponto', mas em situações manuais (arquivos de dados de limpeza) você geralmente não espera 'arquivos de ponto'. Os métodos recursivos, entretanto, são para uma limpeza geral mais automatizada, especialmente em estruturas de diretório muito grandes.
anthony
Em um caso, foi mais complicado porque eu precisei remover diretórios vazios, onde 'vazio' incluía diretórios que poderiam conter um único arquivo 'leia-me'. Qualquer outra coisa no diretório e não estava "vazio". Nesse exemplo, a estrutura de diretório envolvia dezenas de milhares de subdiretórios.
anthony
1

O comando a seguir retorna 1 se um diretório está vazio (ou não existe) e 0 caso contrário (portanto, é possível inverter o código de retorno com !em um script de shell):

find $dir -type d -prune -empty -exec false {} +
Mateusz Piotrowski
fonte
0

Criei uma estrutura simples da seguinte maneira:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

O test/test3/filecontém algum texto inútil.

A emissão find test -emptyretorna " test/test2/test2.2" como o único diretório vazio.

James Sumners
fonte
a operação pede que test / test2 seja retornado também
De fato. Mas achei que ele poderia ler a página de manual de localização para ir mais longe. Um script que ajusta as profundidades com base nos resultados funcionaria muito bem.
James Sumners
Esta foi a versão mais útil para meu uso, obrigado
Andreas
0

uma abordagem simples seria,

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

Além disso,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"
phoenix24
fonte
0
find . -name -type d -ls |awk '($2==0){print $11}'
Vijay
fonte