Я хотел бы вывести список всех файлов в папке с именем, 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