仅查找以 .whl 结尾的文件

仅查找以 .whl 结尾的文件

我正在尝试捕获所有.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/*.文件名将被传递到lsls抱怨该文件(是的) ,*.是 Unix 中完全有效的文件名)不存在。请注意,failglobnullglob选项会改变该行为。

现在,大括号扩展功能来自 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/*.zshcshset -o cshnullglobset +o nomatchbashzshshopt -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首先列出文件,但在lsas 命令的情况下,ls无论如何对列表进行排序都没有区别)。

但请注意,如果由于 Bourne shell 错误功能而没有与该模式匹配的文件,ksh则除非您使用failglobin ,否则bash最终可能会列出一个字面意义上的文件。*.?(whl)

在 中,如果您想在 之前zsh列出文件而不将其视为错误(如果任一列表为空,如/ ),您可以在本地使用:*.whl*.cshfishcshnullglob

(){ set -o localoptions -o cshnullglob; ls -ldU /python/*.{whl,}; }

(这里假设 GNUls并使用其-U选项来禁用其排序)。

或者使用Nglob 限定符(获取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
)

相关内容