我正在尝试捕获所有.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: cannot access /python/*.: No such file or directory
如何解决这个问题,以仅查找以 . 结尾的文件。whl
答案1
如果您只对带有whl
扩展名的文件感兴趣,
ls -l /python/*.whl
这就是你所追求的。
您当前的命令,
ls -l /python/*.{whl,}
相当于
ls -l /python/*.whl /python/*.
(谢谢大括号扩展) 并失败,因为后一个模式与 中的任何内容都不匹配/python
。
答案2
作为@StephenKitt 说说,在 中bash
,大括号扩展是在通配之前完成的(甚至在所有其他形式的扩展(包括参数扩展)之前完成,看看如何是输出和的内容的bash
唯一 shell ),所以,echo $P{S1,ATH}
$PS1
$PATH
ls -l /python/*.{whl,}
是相同的:
ls -l /python/*.whl /python/*.
并且bash
从 Bourne shell 继承的错误功能是不匹配的 glob 会按字面意思传递给命令,因此如果没有/python
名称以 结尾的非隐藏文件.
,/python/*.
文件名将被传递到ls
并ls
抱怨该文件(是的) ,*.
是 Unix 中完全有效的文件名)不存在。请注意,failglob
和nullglob
选项会改变该行为。
现在,大括号扩展功能来自 70 年代末的 csh。您会注意到,您在 中没有看到该错误csh
。
csh
没有 Bourne shell 的缺陷,其行为类似于/etc/glob
早期的 Unices(它的名字是 glob),不匹配的 glob 会被删除(而不是按原样传递),并且如果全部命令行中的 glob 无法匹配,然后命令被取消(明智的做法,因为显然有些问题是错误的)。
所以在csh
:
ls -l /python/*.{whl,}
首先扩展到
ls -l /python/*.whl /python/*.
与 in 类似bash
,但因为/python/*.
不匹配任何文件但/python/*.whl
匹配一些文件,/python/*.
被删除并使用文件ls
列表调用.whl
。
如果也没有任何.whl
文件,你就会有一个No match
错误通过 csh,而不是错误经过ls
关于不存在的文件。
zsh
是另一个从 复制大括号扩展的 shell csh
。不匹配的 glob 的行为是不同的。
zsh
也没有 Bourne shell 的缺陷(至少默认情况下没有),但它会取消命令,只要任何(相对于全部in csh
/ /etc/glob
) glob 无法匹配,因此ls -l /python/*.{whl,}
即使有文件也ls -l /python/*.whl /python/*.
不会运行,因为glob 不匹配。在 中,您可以使用 来获取行为,或者使用 来获取 Bourne 行为(不推荐)。在 中,您可以获得与 with类似的行为。ls
.whl
/python/*.
zsh
csh
set -o cshnullglob
set +o nomatch
bash
zsh
shopt -s failglob
shellfish
的行为却有所不同。
fish
(一个更新的 shell)的行为类似于zsh
失败的 glob 取消命令。就像在 中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,每种情况一个(除非您希望.whl
首先列出文件,但在ls
as 命令的情况下,ls
无论如何对列表进行排序都没有区别)。
但请注意,如果由于 Bourne shell 错误功能而没有与该模式匹配的文件,ksh
则除非您使用failglob
in ,否则bash
最终可能会列出一个字面意义上的文件。*.?(whl)
在 中,如果您想在 之前zsh
列出文件而不将其视为错误(如果任一列表为空,如/ ),您可以在本地使用:*.whl
*.
csh
fish
cshnullglob
(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }
(这里假设 GNUls
并使用其-U
选项来禁用其排序)。
或者使用N
glob 限定符(获取nullglob
行为)并手动执行错误处理(对于两个 glob 都不匹配的情况):
() {
if (($#)); then
ls -ldU -- "$@"
else
echo>&2 No match
return 1
fi
} /python/*.{whl,}
类似的事情可以在 bash 中使用子 shell(因为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
)