use 'find' para procurar diretórios contendo certos tipos de arquivos foo

5

Eu tenho alguns diretórios, alguns com uma profundidade de 3, que contêm tipos de arquivos mistos. O que preciso fazer é rm -rf de todos os subdiretórios que não contêm filetype foo .

Isso é possível com find de alguma forma? Eu sei que eu posso usar encontrar assim:

find . ! -name '*.foo' -delete

para excluir todos os arquivos nos diretórios que não contêm nenhum arquivo do tipo *.foo . Agora, como posso usar isso para excluir não apenas todos os arquivos indesejados, mas todos os diretórios e subdiretórios que não contêm *.foo ?

    
por jottr 01.03.2011 / 02:50

4 respostas

3

(Sua pergunta não está clara: se um diretório contiver some.foo e some.bar , ele deve ser excluído? Eu interpretei isso exigindo que esse diretório seja mantido.)

O script a seguir deve funcionar, desde que nenhum nome de arquivo contenha uma nova linha e nenhum diretório corresponda a *.foo . O princípio é percorrer o diretório das folhas para cima ( -depth ) e, como arquivos *.foo são encontrados, o diretório que o contém e todos os pais são marcados como protected . Qualquer arquivo atingido que não seja *.foo e não protegido é um diretório a ser excluído. Devido à ordem de passagem -depth , um diretório é sempre alcançado após os arquivos *.foo que podem protegê-lo. Aviso: minimamente testado, remova o echo por sua conta e risco.

find . -depth -name '*.foo' -o -type d | awk '{
    if ($0 ~ /\.foo$/) {
        while (sub("/+[^/]+$", "")) {protect[$0]=1;}
    } else {
        if (!protect[$0]) {
            gsub("[\
find . -depth -name '*.foo' -o -type d | awk '{
    if ($0 ~ /\.foo$/) {
        while (sub("/+[^/]+$", "")) {protect[$0]=1;}
    } else {
        if (!protect[$0]) {
            gsub("[\%pre%1-/]", "\\&"); # protect file names for xargs
            print;
        }
    }
}' | xargs echo rm -rf
1-/]", "\\&"); # protect file names for xargs print; } } }' | xargs echo rm -rf

Pela primeira vez, não estou propondo uma solução zsh.

    
por 02.03.2011 / 00:21
2

Não tenho certeza de que isso pode ser feito usando apenas find , mas acho que podemos fazer isso usando apenas bash e find .

tree_contains_foo_files()
{
    # return true (0) as soon as we find a "*.foo" file
    find "$1" -type f -name "*.foo" -print0 |
        read -r -d $'
.
./dir1
./dir1/dir1.1
./dir1/dir1.1/dir1.1.1
./dir1/dir1.1/dir1.1.1/file.foo
./dir1/dir1.1/file.bar
./dir2
./dir2/dir2.1
./dir2/file.bar
./dir3
' file && return 0 return 1 } find . -depth -type d -print0 | while read -r -d $'
rm -rf ./dir2/dir2.1
rm -rf ./dir2
rm -rf ./dir3
' dir; do if ! tree_contains_foo_files "$dir"; then rm -rf "$dir" fi done

Dada esta árvore de teste:

tree_contains_foo_files()
{
    # return true (0) as soon as we find a "*.foo" file
    find "$1" -type f -name "*.foo" -print0 |
        read -r -d $'
.
./dir1
./dir1/dir1.1
./dir1/dir1.1/dir1.1.1
./dir1/dir1.1/dir1.1.1/file.foo
./dir1/dir1.1/file.bar
./dir2
./dir2/dir2.1
./dir2/file.bar
./dir3
' file && return 0 return 1 } find . -depth -type d -print0 | while read -r -d $'
rm -rf ./dir2/dir2.1
rm -rf ./dir2
rm -rf ./dir3
' dir; do if ! tree_contains_foo_files "$dir"; then rm -rf "$dir" fi done

Eu recebo este resultado:

%pre%

que eu acho que é o que você quer, ou seja, não exclua dir1 , porque dir1/dir1.1/dir1.1.1 contém file.foo .

Mas observe que ele processa diretórios várias vezes, portanto, pode ser lento para árvores grandes. Se a eficiência for importante, usaria uma linguagem de programação mais poderosa.

    
por 01.03.2011 / 04:32
1

IIUYC, você pode simplesmente remover todos os arquivos indesejados usando

find . ! -type f -name '*.foo' -delete

que pode esvaziar alguns diretórios. Então você pode remover os diretórios vazios (e diretórios contendo apenas diretórios vazios, etc.) como em minha pergunta

find . -depth -mindepth 1 -empty -type d -exec rmdir -p -- {} +
    
por 02.03.2011 / 17:41
1

Se mais do que apenas find for permitido, uma solução muito mais simples é:

find -type d -not -path . | while IFS='' read -r path; do [[ ! -e "$path/$notThisFile" ]] && echo "$path"; done

Substitua -e por qualquer teste que você goste.

Isso deve imprimir todos os subdiretórios que não contêm $notThisFile .

Exemplo detalhado, em que todos os subdiretórios não ocultos que contêm o arquivo são destacados:

find -type d -not -path . | while IFS='' read -r path; do
  [[ ! -e "$path/$notThisFile" ]] && echo "$path"
done | sed -r 's~^([^.]*)/'"$notThisFile"'$~3[1;37m3[0m~''
    
por 07.01.2017 / 18:28