Encontre diretórios onde faltam arquivos com final específico

10

Eu quero exibir todos os diretórios, que não contêm arquivos com um arquivo específico terminado. Por isso, tentei usar o seguinte código:

find . -type d \! -exec test -e '{}/*.ENDING' \; -print

Neste exemplo, eu queria exibir todos os diretórios, que não contêm arquivos com o final .ENDING , mas isso não funciona.

Onde está o meu erro?

    
por bamboo 16.06.2014 / 15:41

7 respostas

7

Aqui está uma solução em três etapas:

temeraire:tmp jenny$ find . -type f -name \*ENDING -exec dirname {} \; |sort -u > /tmp/ending.lst
temeraire:tmp jenny$ find . -type d |sort -u > /tmp/dirs.lst
temeraire:tmp jenny$ comm -3 /tmp/dirs.lst /tmp/ending.lst 
    
por 16.06.2014 / 16:43
4

Aqui vamos nós!

#!/usr/bin/env python3
import os

for curdir,dirnames,filenames in os.walk('.'):
  if len(tuple(filter(lambda x: x.endswith('.ENDING'), filenames))) == 0:
    print(curdir)

Ou alternadamente (e mais pythonic):

#!/usr/bin/env python3
import os

for curdir,dirnames,filenames in os.walk('.'):
    # Props to Cristian Cliupitu for the better python
    if not any(x.endswith('.ENDING') for x in filenames):
        print(curdir)

Conteúdo DLC bônus!

A versão (principalmente) corrigida do comando find:

find . -type d \! -exec bash -c 'set nullglob; test -f "{}"/*.ENDING' \; -print
    
por 16.06.2014 / 17:56
3

O shell expande o * , mas no seu caso não há shell envolvido, apenas o comando test executado pelo find . Portanto, o arquivo cuja existência é testada é literalmente denominado *.ENDING .

Em vez disso, você deve usar algo assim:

find . -type d \! -execdir sh -c 'test -e {}/*.ENDING' \; -print

Isso resultaria em sh expandindo *.ENDING quando o teste é executado.

Fonte: encontrar globbing no UX.SE

    
por 16.06.2014 / 16:11
2

Inspirado por Dennis Nolte's e Respostas de MikeyB , eu vim com esta solução:

find . -type d                                                           \
  \! -exec bash -c 'shopt -s failglob; echo "{}"/*.ENDING >/dev/null' \; \
  -print 2>/dev/null

Funciona com base no fato de que

if the failglob shell option is set, and no matches are found, an error message is printed and the command is not executed.

A propósito, é por isso que stderr foi redirecionado para /dev/null .

    
por 16.06.2014 / 19:23
1

Eu faria isso pessoalmente no perl

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;


#this sub is called by 'find' on each file it traverses. 
sub checkdir {
    #skip non directories. 
    return unless ( -d $File::Find::name );

    #glob will return an empty array if no files math - which evaluates as 'false'
    if ( not glob ( "$File::Find::name/*.ENDING" ) ) {
        print "$File::Find::name does not contain any files that end with '.ENDING'\n";
    }
}

#kick off the search on '.' - set a directory path or list of directories to taste.
#  - you can specify multiple in a list if you so desire. 
find (  \&checkdir, "." );

Deve fazer o truque (funciona no meu caso de teste muito simplista).

    
por 16.06.2014 / 18:09
0

Aqui está um one-liner.

find ./ -type d ! -regex '.*.ENDING$' -printf "%h\n" | sort -u

Editar : Ops, não funcionará também.

    
por 16.06.2014 / 20:11
0
find . -type d '!' -exec sh -c 'ls -1 "{}"|egrep -q "*ENDING$"' ';' -print
  • q no egrep é para silêncio

  • Com egrep , você pode trocar o regex de que precisa

  • ls -1 "{}" exibe os nomes dos arquivos do comando find

por 14.11.2014 / 23:15