shell globbing 中的匹配零个或多个运算符

Kir*_*ira 10 shell regular-expression wildcards

我在这里遇到了一个非常微不足道的问题:如何使*bash 中的符号表示零或更多,就像在诸如sed? 之类的工具中一样?

例如,ak*应该匹配名称完全由a后跟零个或多个ks组成的任何文件。它的扩张将包括aakakk,和akkk,但不会akc

我已经unsetopt sh_glob在 zsh 和set -o noglobbash 中尝试过;他们没有产生预期的行为。

Gil*_*il' 12

除了ksh93,通常的 shell 都没有与 sed、awk 等语法相同的正则表达式,可用于匹配文件。

Ksh93、bash 和 zsh 的正则表达式具有不同的语法,可向后兼容 globs:

  • ?匹配任何单个字符(就像.通常的正则表达式语法)
  • […] 以几乎相同的方式匹配字符集
  • *(FOO)匹配任意次数的FOO(就像在通常的正则表达式语法中一样)(FOO)*
  • 类似地匹配一次或多次出现,并匹配零次或一次出现+(FOO)?(FOO)
  • @(FOO|BAR)匹配FOOBAR
  • 匹配适用于整个字符串,而不是子字符串;如果你想要一个子串,放在*开头和结尾

此语法需要使用shopt -s extglobin bash 和setopt ksh_globin zsh激活。所以在 bash 你会写

shopt -s extglob
ls a*(k)
Run Code Online (Sandbox Code Playgroud)

另请参阅为什么我的正则表达式适用于 X 而不适用于 Y?

ksh93、zsh 和bash 可以用construct的=~操作符对字符串进行正则表达式与扩展正则表达式(基本上是awk 的语法)的匹配[[ … ]]。虽然这不方便列出文件,但如果你真的想要它,它可以完成。

shopt -s dotglob  # <<< include dot files, for bash
setopt globdots   # <<< include dot files, for zsh
FIGNORE='@(.|..)' # <<< include dot files, for ksh
for x in *; do
  if [[ $x =~ ^ak*$ ]]; then
    …
  fi
done
Run Code Online (Sandbox Code Playgroud)

  • 像“ls a*(k)”这样的简单答案已经让您得到了一个可接受的答案,所以感谢您花时间做出这个彻底的答案。 (2认同)

cas*_*cas 7

ls ak{k,}将显示以开头的文件,ak后跟另一个k或什么都不显示。

$ touch ak akk akc
$ ls -l ak{k,}
-rw-rw-r-- 1 cas cas 0 Oct 27 10:30 ak
-rw-rw-r-- 1 cas cas 0 Oct 27 10:30 akk
Run Code Online (Sandbox Code Playgroud)

globs 不是正则表达式,但它们不仅仅是*and ?

如果要使用正则表达式查找匹配的文件名,可以使用以下find命令:

$ find . -maxdepth 1 -type f -regex './ak+$' 
./ak
./akk
Run Code Online (Sandbox Code Playgroud)

-maxdepth 1选项将搜索限制为仅当前目录(不会搜索子目录)

如果您想要不区分大小写的搜索,请使用-iregex而不是-regex

有许多方法可以使用find在其他命令中找到的文件。例如:

find . -maxdepth 1 -type f -regex './ak+$' -ls
find . -maxdepth 1 -type f -regex './ak+$' -exec ls -ld {} +
find . -maxdepth 1 -type f -regex './ak+$' -print0 | xargs -0r ls -ld
ls -ld $(find . -maxdepth 1 -type f -regex './ak+$')
Run Code Online (Sandbox Code Playgroud)

最后一个例子容易出现各种失败模式,包括 1. 不处理文件名中的空格等,2. 命令行长度限制。不建议。