Я пытаюсь захватить все файлы .whl
как следующее
ls -l /python/*.{whl,}
ls: cannot access /python/*.: No such file or directory
-rw-r--r-- 1 root root 23000 Jun 14 11:02 /python/argparse-1.4.0-py2.py3-none-any.whl
-rw-r--r-- 1 root root 154423 Jun 14 11:02 /python/certifi-2019.9.11-py2.py3-none-any.whl
-rw-r--r-- 1 root root 387834 Jun 14 11:02 /python/cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl
-rw-r--r-- 1 root root 133356 Jun 14 11:02 /python/chardet-3.0.4-py2.py3-none-any.whl
-rw-r--r-- 1 root root 2728298 Jun 14 11:02 /python/cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl
-rw-r--r-- 1 root root 11223 Jun 14 11:02 /python/enum34-1.1.10-py2-none-any.whl
-rw-r--r-- 1 root root 58594 Jun 14 11:02 /python/idna-2.8-py2.py3-none-any.whl
-rw-r--r-- 1 root root 18159 Jun 14 11:02 /python/ipaddress-1.0.23-py2.py3-none-any.whl
-rw-r--r-- 1 root root 125774 Jun 14 11:02 /python/Jinja2-2.11.2-py2.py3-none-any.whl
, но, как вы можете видеть, мы также получаем - ls: невозможно получить доступ к /python/*.: Нет такого файла или каталога
, как это исправить, чтобы найти только файлы, оканчивающиеся на . вл
Если вас интересуют только файлы с расширением whl
,
ls -l /python/*.whl
— это то, что вам нужно.
Ваша текущая команда,
ls -l /python/*.{whl,}
эквивалентно
ls -l /python/*.whl /python/*.
(благодаря раскрытию фигурных скобок )и терпит неудачу, потому что последний шаблон ничему не соответствует в /python
.
Как сказал @StephenKitt, сказал, что в bash
расширение скобок выполняется перед подстановкой (даже перед всеми другими формами расширения, включая раскрытие параметров, см., как bash
является единственной оболочкой где echo $P{S1,ATH}
выводит содержимое как $PS1
, так и $PATH
), поэтому
ls -l /python/*.{whl,}
совпадает с:
ls -l /python/*.whl /python/*.
И bash
имеет эту неверную функцию, унаследованную от оболочки Bourne, которая не совпадает с подстановочными значениями, которые передаются команде буквально, поэтому, если в /python
нет не -скрытого файла, имя которого заканчивается на .
, имя файла /python/*.
будет передано ls
, а ls
жалуется, что этот файл (да, *.
является вполне допустимым именем файла в Unix )не существует. Обратите внимание, что опции failglob
и nullglob
изменяют это поведение.
Теперь функция расширения фигурных скобок пришла из csh в конце 70-х. И вы заметите, что вы не видите эту ошибку в csh
.
csh
не имеет этой неправильной функции оболочки Bourne и ведет себя как /etc/glob
ранних Unices (, которые дали свое имя глобусам )в том, что глобы, которые не совпадают, удаляются (вместо передается как -равно ), и если все глобусы в командной строке не совпадают,затем команда отменяется (разумный поступок, так как явно что-то не так ).
Итак, вcsh
:
ls -l /python/*.{whl,}
сначала расширяется до
ls -l /python/*.whl /python/*.
аналогично bash
, но поскольку /python/*.
не соответствует ни одному файлу, а /python/*.whl
соответствует некоторым файлам, /python/*.
удаляется, а ls
вызывается со списком .whl
файлов.
Если бы не было никакого .whl
файла, у вас была бы No match
ошибка от csh , вместо ошибки отls
о не -существующие файлы.
zsh
— еще одна оболочка, которая скопировала раскрытие фигурных скобок из csh
. Поведение непревзойденных глобусов отличается.
zsh
не имеет этого недостатка оболочки Bourne (, по крайней мере, не по умолчанию ), но отменяет команды до тех пор, пока любые(в отличие от все в csh
//etc/glob
)glob не соответствует, поэтому ls -l /python/*.{whl,}
или ls -l /python/*.whl /python/*.
не будет запускать ls
, даже если есть .whl
файлы, потому что /python/*.
glob не совпадает. В zsh
вы можете получить поведение csh
вместо set -o cshnullglob
или поведение Борна сset +o nomatch
(не рекомендуется ). В bash
вы можете получить поведение, подобное zsh
, с помощью shopt -s failglob
.
Поведение оболочки fish
отличается.
fish
(гораздо более новая оболочка )ведет себя как zsh
в том, что сбойные глобусы отменяют команду. Как и в zsh
, вы увидите, что
ls -l /python/*.whl /python/*.
не запускается ls
и возвращает:
fish: No matches for wildcard “/python/*.”. See `help expand`.
ls -l /python/*.whl /python/*.
^
ошибка. Но
ls -l /python/*.{whl,}
возвращает ли не ошибку, перечисляет файлы .whl
и передает ли не аргумент /python/*.
в ls
в этом случае как csh
.
Но это потому, что хотя {x,y}
и здесь не является, строго говоря, подстановочным оператором, он выполняется наряду с подстановкой, и только если подстановка, выполненная для всей фигурной скобки, не соответствует ни одному файлу, является команда отменена.Вы увидите, что если нет ни файлов *.whl
, ни *.
, ошибка становится:
fish: No matches for wildcard “/python/*.{whl,}”. See `help expand`.
ls -l /python/*.{whl,}
^
То есть весь /python/*.{whl,}
считается подстановочным знаком здесь, а не подстановочным знаком, полученным в результате раскрытия фигурной скобки.
Чтобы перечислить файлы, оканчивающиеся на .whl
или .
, я бы сделал:
ls -ld /python/*(.|.whl) # zsh
ls -ld /python/*.(|whl) # zsh
ls -ld /python/*@(.|.whl) # ksh / bash -O extglob
ls -ld /python/*.?(whl) # ksh / bash -O extglob
То есть используйте оператор glob внутри одного glob, который соответствует либо, а не двум glob, по одному для каждого случая (, если только вы не хотите, чтобы файлы .whl
быть в списке первым, но в случае ls
в качестве команды это не имеет значения, так как ls
все равно сортирует список ).
Однако имейте в виду, что варианты ksh
, если вы не используете failglob
в bash
, могут привести к тому, что -будет содержать список файлов, буквально именуемых *.?(whl)
, если не было файла, соответствующего этому шаблону, из-за неправильной функции оболочки Bourne..
в zsh
, если вы хотите перечислить файлы *.whl
перед *.
, не рассматривая это как ошибку, если какой-либо список пуст, как в csh
/ fish
, вы можете использовать cshnullglob
локально:
(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }
(здесь предполагается GNU ls
и используется его опция -U
для отключения сортировки ).
Или используйте квалификатор N
glob (, чтобы получить nullglob
поведение )и выполнить обработку ошибок (для случая, когда ни один glob не соответствует )вручную:
() {
if (($#)); then
ls -ldU -- "$@"
else
echo>&2 No match
return 1
fi
} /python/*.{whl,}
Нечто подобное можно было бы сделать в bash с помощью подоболочки (, поскольку bash
не имеет анонимных функций )для ограничения объема опций и позиционных параметров:
(
shopt -s nullglob
shopt -u failglob # failglob takes precedence over nullglob when set!
set -- /python/*.{whl,}
if (($#)); then
ls -ldU -- "$@"
else
echo>&2 No match
exit 1
fi
)