Ignora todas as correspondências para o padrão extglob negado em sls recursivo

1

Gostaria de listar recursivamente todos os arquivos em um diretório que correspondam a um determinado padrão de entrada usando ls . (Ah, e isso é no Bash).

A única maneira que posso pensar em fazer isso usando ls é shopt -s extglob e, em seguida, use a opção ls --ignore=pattern com o padrão de negação de glob estendido !( pattern-list ) . Parece um tipo de rotatória para negar em um ignorar, mas de outra forma os curingas não são válidos.

Supondo que eu já tenha o diretório para procurar como dir e o padrão para corresponder como file , esta é minha tentativa atual:

ls -AR --ignore='!('"${file}"')' ${dir}

No entanto, isso não parece ter o efeito desejado, por exemplo, em um caso de teste em que a estrutura de diretórios fornece essa saída para ls -AR :

    .:
    a  a.c  b  b.c  c  c.h  s

    ./s:
    a  a.c  b  b.c  c  c.h

Meu comando com file = *.c e dir = s (comando completo: ls -AR --ignore=!(*.c) s ) fornece esta saída:

    ./s:
    a  a.c  b  b.c  c  c.h

Eu sei que eu poderia canalizá-lo para o grep facilmente, e fazer algo como ls -AR s | grep -v '.*.c' e obter uma saída como:

    s:
    a
    b
    c
    c.h

mas estou procurando uma maneira de fazer isso apenas por meio de ls .

Desculpe se não estava claro, esta é minha primeira vez em um site do StackExchange.

Obrigado antecipadamente!

    
por samebertz 13.02.2013 / 22:37

2 respostas

3

Que tal adicionar a opção globstar shell e o -d flag a ls para não listar automaticamente o conteúdo do diretório?

shopt -s extglob
shopt -s globstar
ls -d  **/!(*.c)
    
por 13.02.2013 / 22:49
2
A opção

GNU ls --ignore usa padrões de nome de arquivo padrão, e não ksh estendida (que bash (e bash apenas, não ls ) reconhece com extglob )

Então você pode fazer:

ls -AR --ignore='*.[ch]' --ignore='*.cpp'

Mas você não pode fazer:

ls -AR --ignore='!(*.[ch]|*.cpp)'

O que apenas ignoraria arquivos com o nome: !(foo.c|bar.cpp) .

Em ls -AR --ignore=!(*.c) , como o padrão não é citado, bash tentaria expandi-lo antes de passá-lo para ls . Por isso, no diretório atual, procuraria arquivos cujos nomes começassem com "--ignore=" e não terminassem em ".c" . Por exemplo, se houvesse dois arquivos, um chamado --ignore=foo e um chamado --ignore=bar , ele executaria ls com esses quatro argumentos: "ls" , "-AR" , "--ignore=bar" , "--ignore=foo" .

Você pode fazer (com o GNU find).

find . -regextype posix-extended -regex '.*\.([ch]|cpp)' -ls

Ou com qualquer POSIX find :

find . \( -name '*.[ch]' -o -name '*.cpp' \) -exec ls -ld {} +

Ou supondo que não haja links simbólicos para os diretórios:

shopt -s extglob globstar dotglob failglob
ls -ld -- **/*.@([ch]|cpp)

Desta vez, bash expande o padrão de globbing e passa a lista de arquivos para ls .

    
por 13.02.2013 / 22:54