procura por diretórios contendo um arquivo e faltando outro

3

No momento, estou ciente de como pesquisar diretórios e listar os que NÃO contêm um arquivo específico como este:

find parent_directory -mindepth 1 -maxdepth 1 -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^file_name$"' \; -print

mas agora desejo usar os diretórios resultantes para verificar se eles contêm ou não outro arquivo, mas não consigo fazer isso em uma expressão estendida de uma linha. Isso é possível de alguma forma?

    
por uitty400 24.07.2017 / 11:05

3 respostas

3

Você está tornando isso muito mais complicado do que o necessário. Você não parece querer recorrer a subdiretórios, então tudo que você precisa para encontrar esses diretórios que não possuem um arquivo específico é:

for dir in */; do [ ! -e "$dir"/"$filename" ] || printf '%s\n' "$dir"; done

E para ver quais deles têm outro arquivo:

for dir in */; do 
    [ ! -e "$dir"/"$filename1" ] && 
    [ -e "$dir"/"$filename2" ] && 
    printf '%s\n' "$dir"; 
done

Ou, em uma sintaxe ligeiramente mais clara:

for dir in */; do 
    if [ ! -e "$dir"/"$filename1" ]; then 
        if [ -e "$dir"/"$filename2" ]; then 
            printf '%s\n' "$dir"; 
        fi 
    fi
 done

Tudo isso é feito usando as ferramentas internas do shell. Especificamente:

  • [ : this, e os ] associados são sinônimos para o test construído (veja help [ ou help test se estiver usando um shell sh-style). São formas de escrever operações de teste no shell.
  • -e : testa se existe um arquivo / diretório, etc. Veja help test . O formato simples é: [ -e file ] , que retornará verdadeiro se file existir.
  • [ ! -e filename ] : o ! simplesmente inverte o teste. Portanto, [ ! -e file ] será verdadeiro se file não existir.

Juntos, isso significa que o comando acima faz:

## Iterate over every directory (dirs only because of the '/' in '*/')
## saving each of them in the variable $dir.
for dir in */; do 
    ## If this $dir does not contain $filename1
    if [ ! -e "$dir"/"$filename1" ]; then 
        ## If this $dir does contain $filename2
        if [ -e "$dir"/"$filename2" ]; then 
            ## Print the directory name
            printf '%s\n' "$dir"; 
        fi 
    fi
done

Para executar isso, é claro, primeiro é necessário definir $filename1 e $filename2 de acordo. Por exemplo:

filename1="unwantedFile"
filename2="wantedFile"
    
por 24.07.2017 / 11:18
4

Você também pode determinar seus diretórios necessários da seguinte maneira:

find . -maxdepth 2 -path '*/*/wanted.txt' -type f \
  -execdir test ! -f unwanted.txt \; -execdir pwd \;

Como isso funciona é o seguinte:

  • Procuramos entradas até a profundidade de 2.
  • A opção -path irá constrangi-los a serem exatamente uma profundidade de 2 devido à presença de duas barras, pois a profundidade máxima impedirá de ir mais longe e duas barras explícitas evitam ir abaixo da profundidade de 2.
  • A entrada wanted.txt encontrada no nível de profundidade 2 é melhor que um arquivo regular assegurado por -type f
  • A opção -execdir elevará a operação para o diretório no qual o wanted.txt reside e, portanto, o comando test procurará o arquivo indesejado lá.
  • Em seguida, é simples imprimir o diretório (elevado devido a -execdir ) onde o arquivo indesejado não foi encontrado.
  • Sem querer insistir nesse ponto, um diretório pode conter um arquivo específico apenas uma vez, portanto, as operações -execdir são executadas uma vez por diretório e apenas nesses diretórios que, pelo menos, contêm arquivos regulares de wanted.txt. / li>
por 24.07.2017 / 12:48
3

Com zsh , para listar os diretórios no diretório atual que contêm um arquivo musthave e não um arquivo mustnothave :

contain() [[ -e $REPLY/$1 || -L $REPLY/$1 ]]

printf '%s\n' *(D/e(contain musthave)^e(contain mustnothave))

Observe que fazendo:

find ... -exec sh -c 'ls {}' \;

não é apenas não portátil, mas também é uma vulnerabilidade de injeção de comando. Por exemplo, se houver um diretório chamado $(reboot) ou ;reboot , isso executaria as linhas de comando ls $(reboot) ou ls ;reboot causando uma reinicialização. {} nunca deve ser incorporado em um argumento de código (de sh ou qualquer outro idioma) onde possa ser mal interpretado. Use:

find ... -exec sh -c 'ls "$1"' sh {} \;

em vez disso.

    
por 24.07.2017 / 13:12

Tags