Ignora "sem correspondências"

8

Eu gostaria de listar todos os arquivos em uma pasta chamada foldernameque têm a extensão test, atestou btest.

Meu pensamento imediato foi correr ls ./foldername/*.{a,b,}test

Isso funciona bem, a menos que não exista nada com a extensão atest; nesse caso, recebo o erro zsh: no matches found: ./foldername/*.atest.

Existe alguma maneira de simplesmente ignorar esse erro e imprimir os arquivos que existem?

Eu preciso que isso funcione tanto no ZSH quanto no BASH.

Jonathan Hodgson
fonte
3
Redirecionar erro padrão para /dev/null?
DopeGhoti

Respostas:

9

Talvez seja melhor fazer isso com find:

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'
John Moon
fonte
1
talvez com um -maxdepth 1, para emular mais perto o lscomportamento
Jeff Schaller
4
@JeffSchaller, observe que -maxdepthé uma extensão GNU. Nota 3 outras diferenças com globs: findincluiria arquivos ocultos, não tipo da lista e deixar de coincidir com nomes de arquivos que contêm bytes não formando caracteres válidos (como uma $'St\xe9phane.atest'em um locale UTF-8)
Stéphane Chazelas
11

No

ls -d ./foldername/*.{a,b,}test

{a,b,...} não é um operador da glob, isso é expansão de braçadeira, primeiro expandido para:

ls -d ./foldername/*.atest ./foldername/*.btest ./foldername/*.test

E cada glob expandido individualmente e, se algum glob não corresponder, o comando será cancelado conforme o esperado em zsh(ou fish; in bash, você precisará da failglobopção para obter um comportamento semelhante).

Aqui, você deseja usar um único globo que corresponda a todos esses arquivos e cancelar o comando apenas se esse globo não corresponder a nenhum arquivo:

ls -d ./foldername/*.(a|b|)test

Você não deseja usar nullglob, como se nenhum dos globs correspondesse, ele seria executado lssem argumentos, portanto, liste o diretório atual. cshnullglobé melhor nesse sentido, pois remove globs não correspondentes, mas ainda cancela o comando se todos os globs falharem.

Você não gostaria de usar nonomatch, pois isso daria a você o comportamento quebrado, o bashque seria uma pena.

Para uma alternativa global que funcione em ambos zshe bash, você pode usar os globos ksh ( set -o kshglobin zshe shopt -s extglobin bash).

Então, você faria:

ls -d ./foldername/*.@(a|b|)test

ou:

ls -d ./foldername/*.?([ab])test

Adicione a failglobopção bashpara evitar que o glob seja transmitido literalmente para lsquando não corresponder.

Consulte Por que o nullglob não é o padrão? Para maiores informações.

Stéphane Chazelas
fonte
Não sei por que é um requisito do OP, mas existe um extglob que funciona para isso no bash e no zsh? Eu tive que usar ?(...)ou +(...)para o bash.
Jeff Schaller
@JeffSchaller, consulte edit #
Stéphane Chazelas