Bash 扩展通配符

Bash 扩展通配符

我无法从ls使用 bash 扩展通配符的输出中仅显示一个文件。

info bash

  If the `extglob' shell option is enabled using the `shopt' builtin,
several extended pattern matching operators are recognized.  In the
following description, a PATTERN-LIST is a list of one or more patterns
separated by a `|'.  Composite patterns may be formed using one or more
of the following sub-patterns:

`?(PATTERN-LIST)'
     Matches zero or one occurrence of the given patterns.

`*(PATTERN-LIST)'
     Matches zero or more occurrences of the given patterns.

`+(PATTERN-LIST)'
     Matches one or more occurrences of the given patterns.

`@(PATTERN-LIST)'
     Matches exactly one of the given patterns.

`!(PATTERN-LIST)'
     Matches anything except one of the given patterns.

shops -s extglob

ls -l /boot/@(vmlinuz*)
-rw-r--r--  1 root root 1829516 Apr 21  2009 /boot/vmlinuz-2.6.9-89.EL
-rw-r--r--  1 root root 1700492 Apr 21  2009 /boot/vmlinuz-2.6.9-89.ELsmp

ls -l /boot/?(vmlinuz*)
-rw-r--r--  1 root root 1829516 Apr 21  2009 /boot/vmlinuz-2.6.9-89.EL
-rw-r--r--  1 root root 1700492 Apr 21  2009 /boot/vmlinuz-2.6.9-89.ELsmp

如何只显示一个文件?

答案1

Bash 没有功能可以仅扩展多个匹配项中的一个。

该模式@(foo)仅匹配一个发生的图案foo。也就是说,它匹配foo,但不匹配foofoo。这种语法形式对于构建 或 之类的模式很有用@(foo|bar),它匹配foobar。它可以用作较长模式的一部分,例如@(foo|bar)-*.txt, 匹配foo-hello.txt, foo-42.txt,bar-42.txt等。

如果要使用多个匹配项中的一个,可以将匹配项放入一个数组中,然后使用该数组的一个元素。

kernels=(vmlinuz*)
ls -l "${kernels[0]}"

匹配项始终按字典顺序排序,因此这将按字典顺序打印第一个匹配项。

请注意,如果模式与任何文件都不匹配,您将获得一个包含单个元素的数组,该元素是未更改的模式:

$ a=(doesnotmatchanything*)
$ ls -l "${a[0]}"
ls: cannot access doesnotmatchanything*: No such file or directory

设置nullglob选项以获取空数组。

shopt -s nullglob
kernels=(vmlinuz*)
if ((${#kernels[@]} == 0)); then
  echo "No kernels here"
else
  echo "One of the ${#kernels[@]} kernels is ${kernels[0]}"
fi

Zsh 这里有方便的功能。这全局限定符 [NUM]导致模式扩展到仅第 NUM 个匹配;该变体扩展到第 NUM1 个到第 NUM2 个匹配项(从 1 开始)。[NUM1,NUM2]

% ls -l vmlinuz*([1])
lrwxrwxrwx 1 root root 26 Nov 15 21:12 vmlinuz -> vmlinuz-3.16-0.bpo.3-amd64
% ls -l nosuchfilehere*([1])
zsh: no matches found: nosuchfilehere*([1])

如果没有文件匹配,则glob 限定符N会导致模式扩展为空列表。

kernels=(vmlinuz*(N))
if ((#kernels)); then
  ls -l $kernels
else
  echo "No kernels here"
fi

glob 限定符om通过增加年龄而不是按名称(m用于修改时间)对匹配项进行排序;Om按年龄递减排序。因此vmlinuz*(om[1])扩展到最新的内核文件。

答案2

“一场比赛”并不意味着你所认为的那样。它的意思是模式内的一场比赛,而不是只返回一个文件。ls没有这样的选项。通常,人们会做类似的事情ls |head -1

相关内容