Linux: exclua todos os diretórios com apenas um arquivo e nenhum subdiretório

1

Como posso excluir todos os diretórios / subdiretórios de uma árvore que correspondam às seguintes condições:

  1. Diretório não contém outro subdiretório
  2. O diretório contém apenas um arquivo que corresponde a esse padrão de expressão: ^ \ d {10} .jpg $ (dez dígitos com extensão .jpg)

A execução do seguinte comando retornará as pastas desejadas, mas também retornará diretórios com subdiretórios

find . -type d -exec sh -c 'set -- "$0"/*.jpg; [ $# -le 1 ]' {} \; -print
    
por SYNCRo 10.03.2014 / 12:24

2 respostas

2

As pessoas têm um fascínio com os one-liners (embora seja possível escrever scripts de comprimentos arbitrários que geralmente deixam as coisas mais claras), então deixe-me primeiro compactá-lo em uma única linha de Bash :-):

shopt -s globstar; for d in **/; do f=("$d"/*); [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]] && echo rm -r -- "$d"; done

onde echo é uma proteção durante o teste.

O mesmo código em uma versão de script muito mais legível e comentada:

#!/bin/bash

# Enable double asterisk globbing (see 'man bash').
shopt -s globstar

# Loop through every subdirectory.
for d in **/; do
    # Glob a list of the files in the directory.
    f=("$d"/*)
    # If
    # 1. there is exactly 1 entry in the directory
    # 2. it is a file
    # 3. the file name consists of 10 digits with a ".jpg" suffix:
    if [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]]; then
        # 'echo' to ensure a test run; remove when verified.
        echo rm -r -- "$d"
    fi
done

A correspondência é pura Bash (versão ≥4), e acredito que não seja vulnerável a nomes de arquivos "complicados", devido à globbing. Por padrão, ele funciona a partir do diretório atual, mas pode ser modificado para funcionar em um determinado argumento, em um caminho codificado, etc.

ADDITION : Para executar a ordem de subdiretórios em sentido inverso para evitar a necessidade de várias iterações se isso for um problema, primeiro é possível armazenar os subdiretórios em uma variável e, em seguida, percorrê-la de trás para frente da seguinte forma:

#!/bin/bash

# Enable double asterisk globbing (see 'man bash').
shopt -s globstar

# Glob every subdirectory.
subdirs=(**/)

# Loop directories in backwards lexical order to avoid multiple iterations.
for ((i=${#subdirs[@]}; i>0; --i)); do
    d=${subdirs[i-1]}
    # Glob a list of the files in the directory.
    f=("$d"/*)
    # If
    # 1. there is exactly 1 entry in the directory
    # 2. it is a file
    # 3. the file name consists of 10 digits with a ".jpg" suffix:
    if [[ ${#f[@]} -eq 1 && -f "$f" && "${f##*/}" =~ ^[0-9]{10}\.jpg$ ]]; then
        # 'echo' to ensure a test run; remove when verified.
        echo rm -r -- "$d"
    fi
done

Eu acho que isso resolverá o problema no comentário, onde alguns diretórios se tornam elegíveis para remoção somente após os subdiretórios terem sido manipulados (não atualizarei o one-liner, mas todos estão livres para fazer isso sozinhos :-) ).

    
por 10.03.2014 / 14:24
0

Salve a saída do seu comando e a saída desse comando:

ls -lR | awk -F: '!($0 ~ ORS "d") && $0 ORS ~ "-" {print $1}' RS=

(Este encontra diretórios sem subdiretórios)

E use o comando "comm" para verificar linhas semelhantes, talvez?

    
por 10.03.2014 / 12:42

Tags