игнорировать «нет совпадений»

8

Я хотел бы перечислить все файлы в папке , foldernameкоторые имеют расширение test, atestили btest.

Моей непосредственной мыслью было бежать ls ./foldername/*.{a,b,}test

Это прекрасно работает, если нет ничего с расширением atest, в этом случае я получаю ошибку zsh: no matches found: ./foldername/*.atest.

Есть ли способ, которым я могу просто проигнорировать эту ошибку и распечатать файлы, которые существуют?

Мне нужно, чтобы это работало как в ZSH, так и в BASH.

Джонатан Ходжсон
источник
3
Перенаправить стандартную ошибку на /dev/null?
DopeGhoti

Ответы:

9

Лучше всего сделать это с find:

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'
Джон Мун
источник
1
возможно с -maxdepth 1, чтобы ближе подражать lsповедению
Джефф Шаллер
4
@JeffSchaller, обратите внимание, что -maxdepthэто расширение GNU. Обратите внимание на 3 других различия с глобусами: findбудут включать в себя скрытые файлы, не сортировать список и не соответствовать именам файлов, которые содержат байты, не образующие допустимых символов (например, $'St\xe9phane.atest'в локали UTF-8)
Стефан
11

В

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

{a,b,...} это не глобальный оператор, это расширение скобки, которое сначала расширяется до:

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

И каждый глобус расширяется индивидуально, и, если какой-либо глобус не совпадает, команда отменяется, как и следовало ожидать zsh(или fish; bashвам нужна failglobопция для получения аналогичного поведения).

Здесь вы хотите использовать один глобус, который соответствует всем этим файлам, и отменять команду, только если этот глобус не соответствует ни одному файлу:

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

Вы не хотите использовать nullglob, как если бы ни один из глобусов не совпадал, он работал бы lsбез аргументов, поэтому перечислите текущий каталог. cshnullglobлучше в этом отношении, поскольку он удаляет несовпадающие глобусы, но все равно отменяет команду, если все глобусы не совпадают.

Вы не хотели бы использовать nonomatch, поскольку это дало бы вам нарушенное поведение, bashкоторое было бы позором.

Для альтернативы glob, которая работает как в, так zshи в bash, вы можете использовать глобусы ksh ( set -o kshglobin zshи shopt -s extglobin bash).

Тогда вы бы сделали:

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

или:

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

Добавьте failglobопцию, bashчтобы глобус не передавался буквально, lsкогда он не совпадает.

См. Почему nullglob не используется по умолчанию? за дополнительной информацией.

Стефан Шазелас
источник
Я не уверен, почему это требование OP, но есть ли extglob, который работает для этого как в bash, так и в zsh? Я должен был использовать ?(...)или +(...)для Баш.
Джефф Шаллер
@JeffSchaller, см. Редактирование
Стефан