Игнорировать «no matches» из zsh при использовании раскрытия фигурных скобок с glob *.{a,b,}test

Игнорировать «no matches» из zsh при использовании раскрытия фигурных скобок с glob *.{a,b,}test

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

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

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

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

Мне нужно, чтобы это работало и в zsh, и в Bash.

решение1

В

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 globs ( set -o kshglobв zshи shopt -s extglobв bash).

Затем вам нужно сделать следующее:

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

или:

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

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

ВидетьПочему nullglob не является значением по умолчанию?Чтобы получить больше информации.

решение2

Возможно, лучше всего это сделать с помощью find:

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'

решение3

Я столкнулся с этой проблемой и решил ее сначала, взломав сам ls. Закончив, я понял, что мне нужна была только тривальная программа на C:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
  struct stat statbuf;
  int i;
  for( i=1; i<argc; i++ ) {
    if( stat(argv[i],&statbuf) == 0 ) {
      printf("%s\n",argv[i]);
    }
  }
}

Все, что он делает, и все, что ему нужно сделать, — это просмотреть аргументы командной строки и вывести те строки, которые соответствуют допустимым файлам (то есть, для которых stat() завершается успешно).

Конечно, мы можем эмулировать это с помощью столь же простого Python, Perl или даже функции оболочки, которая запускает stat, но написание этого на языке C делает его гораздо более быстрым в выполнении.

Что касается взлома ls, я изложил это на своей личной вики:http://linux.chalisque.net/LsIgnoreMissing

решение4

Комментарий от @DopeGhoti мне помог.

т.е. перенаправляем ошибку на /dev/nullиспользование 2>оператора следующим образом:

ls ./foldername/*.{a,b,}test 2> /dev/null

Связанный контент