Use globbing estendido para listar arquivos, mas não diretórios no bash

1

Digamos que eu tenha a seguinte árvore de diretórios:

.
├── 11
├── 111
├── 112
├── 1121
├── 113
├── 11a
├── 11a1
├── 1a1
├── 1a2
├── 1aa1.png
├── 2a1
├── a.
├── a1a
├── a1a.jpg
├── a2a
├── aa
├── -aa
├── aa.gif
├── aa.jpg
├── aa.png
├── aa.tiff
├── a.exe
├── a.gif
├── a.html
├── a.jpg
├── a.png
├── a.tiff
├── b2
├── b2a
├── ba.gif
├── ba.jpg
├── ba.png
├── ba.tiff
├── b.html
├── cb1.png
├── d.gif
└── sub1
    ├── d.gif
    └── sub2

Então, se eu quiser combinar tudo. ($ PWD) mas arquivos com extensão ".jpg", eu faço o seguinte:

ls !(*.jpg)

Mas o resultado é:

11   1121  11a1  1aa1.png  a1a  aa.gif   a.exe   a.png   b2a     ba.tiff  d.gif
111  113   1a1   2a1       a2a  aa.png   a.gif   a.tiff  ba.gif  b.html   .gif
112  11a   1a2   a.        aa   aa.tiff  a.html  b2      ba.png  cb1.png

sub1:
.  ..  d.gif  sub2

Gostaria de excluir tanto o sub1 como todo o seu conteúdo (até diretórios), por exemplo:

sub1:
.  ..  d.gif  sub2

Eu posso excluir usando:

GLOBIGNORE='sub1' antes de ls, mas o que acontece se eu tiver mais diretórios com nomes diferentes?

Existe uma maneira de fazer isso?

    
por sebelk 26.06.2017 / 20:04

4 respostas

3

Remova a solução:

ls -pd !(*.jpg) | grep -Ev /$

Detalhes

Seu padrão glob não desce em subdiretórios. ls faz: se você passar um diretório em sua linha de comando, ele exibe o conteúdo desse diretório.

Substitua ls por echo :

$ echo !(*.jpg)

Ou, uma solução (quase) equivalente: diga ls para não entrar nos diretórios.

$ ls -d !(*.jpg)

Para responder a pergunta nos comentários: "como usar o comando ls para listar apenas arquivos e não pastas?" Existem algumas opções:

O caminho curto para listar apenas diretórios é:

echo */

Então, talvez, a resposta para listar apenas arquivos e não diretórios pode usar um grep -v

$ ls -p | grep -Ev /$

$ find . -maxdepth 1 ! -type d

Observe que o find listará os arquivos de pontos (arquivos ocultos). E find . -type d (também) não segue links simbólicos.

Ou o loop pragmático (posix):

$ for f in * ; do if [ -f "$f" ] ; then echo "$f" ; fi ; done

É claro que a solução específica para uma expansão negada deve ser assim:

$ ls -pd !(*.jpg) | grep -Ev /$
11
111
112
1121
113
11a
11a1
1a1
1a2
1aa1.png
2a1
a.
a1a
a2a
aa
aa.gif
aa.png
aa.tiff
a.exe
a.gif
a.html
a.png
a.tiff
b2
b2a
ba.gif
ba.png
ba.tiff
b.html
cb1.png
d.gif

Nota:

A opção -p junto com o grep faz o truque para identificar os diretórios, dê uma olhada na página do manual ls:

-p, --file-type, --indicator-style=file-type

    
por 26.06.2017 / 20:23
3

O shell deve ser bash ? Com ZSH e EXTENDED_GLOB set, é possível usar (.) para qualificar () uma expressão glob para apenas arquivos simples . :

$ PS1='%% ' zsh -f
% setopt EXTENDED_GLOB
% mkdir foo && cd foo
% touch nope.jpg
% mkdir sub1
% touch asdf
% print ^*.jpg
asdf sub1
% print ^*.jpg(.)
asdf
% 
    
por 26.06.2017 / 20:18
-1

Você pode canalizar a saída de ls em um filtro grep , como:

ls * | grep -v "jpg"

Para retornar todos os correspondidos que não contenham a string "jpg". (O sinal grep -v inverte a correspondência, retornando todas as linhas que não contêm a string especificada.)

    
por 26.06.2017 / 20:17
-1

I can exclude using: GLOBIGNORE='sub1' before of ls, but what happens if I have more directories with differents names?

No Manual de referência do bash , o GLOBIGNORE é:

A colon-separated list of patterns defining the set of filenames to be ignored by filename expansion. If a filename matched by a filename expansion pattern also matches one of the patterns in GLOBIGNORE, it is removed from the list of matches. The pattern matching honors the setting of the extglob shell option.

    
por 26.06.2017 / 20:25