Como abrir ou listar todos os arquivos cujo nome corresponda a dois padrões no Bash

2

Suponha que eu tenha um diretório com milhares de arquivos; Como eu poderia abrir todos os arquivos cujo nome contém as seqüências de caracteres "vermelho" e "verde"?

    
por James Shapiro 02.06.2016 / 02:27

4 respostas

2

(Supondo que você esteja procurando por arquivos nomes que contenham ambos a string "red" e a string "green" )

Para usar inutilmente o bash para testar nomes de arquivos contra 'red' e 'green' usando o operador de correspondência de expressão regular =~ :

for f in *
do
  [[ $f =~ red && $f =~ green ]] && echo Bash: yes: "$f" || echo Bash: no: "$f"
done

Para usar a sintaxe padrão do shell usando case e globs para encontrar os mesmos arquivos:

for f in *
do 
  case "$f" in
    *green*red*|*red*green*) echo Case: yes: $f;; 
    *) echo Case: no: $f;; 
  esac
done

Ainda mais simples, com a globalização da sua concha:

printf "Glob: %s\n" *green*red* *red*green*

Execução da amostra:

$ touch a b aredgreenb agreenredb agreenbred aredbgreen red green redgreen greenred

$ for f in *
>     do
>       [[ $f =~ red && $f =~ green ]] && echo Bash: yes: "$f" || echo Bash: no: "$f"
>     done
Bash: no: a
Bash: yes: agreenbred
Bash: yes: agreenredb
Bash: yes: aredbgreen
Bash: yes: aredgreenb
Bash: no: b
Bash: no: green
Bash: yes: greenred
Bash: no: red
Bash: yes: redgreen


$ for f in *
>     do
>       case "$f" in
>         *green*red*|*red*green*) echo Case: yes: $f;;
>         *) echo Case: no: $f;;
>       esac
>     done
Case: no: a
Case: yes: agreenbred
Case: yes: agreenredb
Case: yes: aredbgreen
Case: yes: aredgreenb
Case: no: b
Case: no: green
Case: yes: greenred
Case: no: red
Case: yes: redgreen

$ printf "Glob: %s\n" *green*red* *red*green*
Glob: agreenbred
Glob: agreenredb
Glob: greenred
Glob: aredbgreen
Glob: aredgreenb
Glob: redgreen
    
por 02.06.2016 / 03:17
4

com zsh :

set -o extendedglob # best in ~/.zshrc
ls -ld -- *green*~^*red*

O operador ~ glob é para exceto ( e não ). ^ é para não . Então a combinação é e não não , então e . IOW, que corresponde a arquivos com green em seus nomes, exceto aqueles que não contêm red .

Uma alternativa usando o operador de negação ^ (também requer extendedglob ):

ls -ld -- ^(^*green*|^*red*)

tudo menos os arquivos que não contêm verde ou não contêm vermelho.

Para incluir também arquivos ocultos, adicione o qualificador (D) glob.

Você também pode usar qualificadores glob para combinar nomes de arquivos contra regexps, e com setopt rematchpcre , você pode fazer aqueles regexps PCRE, onde você pode usar os operadores look ahead para alcançar e :

re() {
  setopt localoptions rematchpcre
  [[ $REPLY =~ $1 ]]
}
ls -ld -- *(e:'re "(?=.*green).*red"':)

Ou:

re() {
  setopt localoptions rematchpcre
  [[ $REPLY =~ $RE ]]
}
RE='(?=.*green).*red'; ls -ld -- *(+re)

Com ksh ou bash -O extglob ou zsh -o kshglob

ls -ld -- !(!(*green*)|!(*red*))

!(pattern) sendo o ksh equivalente do operador% glob% extendedzsh.

Você também pode fazer:

ls -ld -- @(*green*red*|*red*green*)

Mas isso não é generalizável para nenhum padrão. Por exemplo, para arquivos que contêm ^pattern e abc , você precisa de bcd , para o arquivo correspondente a @(*abc*bcd*|*abcd*|*bcd*abc*) e ??? , *x* ...

com @(x??|?x?|??x)

ksh93 tem alguns operadores e globbing:

ls -ld -- @(*green*&*red*)

Ou usando os seus regexps aumentados (introduzidos com o operador ksh93 glob):

ls -ld -- ~(A:.*green.*&.*red.*)

Você também pode usar os operadores ~(A:...) look ahead em perl-like :

ls -ld -- ~(P:(?=.*green).*red.*)
    
por 02.06.2016 / 13:21
3
find . -type f -name '*red*' -name '*green*'  -exec echo {} +

Substitua echo por vi , gvim , less ou o comando com o qual você deseja abrir os arquivos.

Note que alguns programas não podem manipular vários nomes de arquivos na linha de comando. Se o programa escolhido for um desses, substitua o + no final da linha por \; . Isso executará o comando uma vez para cada nome de arquivo, em vez de apenas uma vez com uma longa lista de nomes de arquivos.

xdg-open é um desses comandos. Ele detecta o tipo de arquivo que está sendo solicitado a abrir e, em seguida, usa o programa padrão do sistema (ou seu programa preferido, se você tiver substituído o padrão) para abrir o arquivo. Se não reconhecer o tipo do arquivo, ele perguntará o que abri-lo.

Usá-lo com find como isso é útil e meio chato ao mesmo tempo. Experimente e você verá por que (você verá muitas janelas abrindo, uma após a outra ... uma para cada nome de arquivo correspondente).

find . -type f -name '*red*' -name '*green*' -exec xdg-open {} \;

BTW, se você quiser encontrar arquivos correspondentes a *red* OU *green* , será necessário usar parênteses para especificar precedência para "e" ( -a ) e "ou "( -o ) operadores. BTW, quando você executa find com vários predicados como acima, o operador padrão é um -a , ou seja, os predicados são logicamente AND-ed juntos.

Os parênteses também têm um significado especial para o shell, portanto, precisam ser escapados com contrabaras para que sejam transmitidos ao comando find, em vez de serem interpretados pelo shell.

find . -type f \( -name '*red*' -o -name '*green*' \) -exec echo {} +

Leia isto como "um arquivo normal AND (um nome de arquivo correspondente a '* red *' OR '* green *')"

    
por 02.06.2016 / 11:09
0

Simples, supondo que o comando open possa manipular vários argumentos:

open *red* *green*

Edit: desculpe, eu estava lendo a pergunta como abertura (arquivos com vermelho no nome) e (arquivos com verde no nome); meu erro.

O seguinte usa extglob e evita a contagem dupla no caso de arquivos chamados redgreenred :

$ shopt -s extglob     # turn on extended globbing
$ printf "extglob: %s\n" @(*green*red*|*red*green*)
extglob: agreenbred
extglob: agreenredb
extglob: aredbgreen
extglob: aredgreenb
extglob: greenred
extglob: redgreen
extglob: redgreenred
$ shopt -u extglob     # turn off extended globbing
    
por 02.06.2016 / 02:32