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

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

我在这里陷入了一个非常微不足道的问题:如何使*bash 中的符号有意义零个或多个,就像它在工具中所做的那样sed

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

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

答案1

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

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

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

shopt -s extglob此语法需要在 bash 和zsh 中激活setopt ksh_glob。所以在 bash 中你会写

shopt -s extglob
ls a*(k)

也可以看看为什么我的正则表达式在 X 中有效但在 Y 中无效?

=~Ksh93、zsh 和 bash 可以使用构造的运算符在字符串上与扩展正则表达式(基本上是 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

答案2

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

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

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

$ find . -maxdepth 1 -type f -regex './ak+$' 
./ak
./akk

-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+$')

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

答案3

您可以使用的语法bash是: ls a+(k) 这取决于启用的bash shoptshell 选项。extglob在 Ubuntu 14.04 GNU/Linux 上,这似乎是默认启用的。

它是这样工作的:

$ shopt extglob
extglob         on
$ ls
ak  akc  akd  akk  akkk  akkkk
$ ls a+(k)
ak  akk  akkk  akkkk
$ shopt -u extglob
$ shopt extglob
extglob         off
$ ls a+(k)
bash: syntax error near unexpected token `('
$

来自 Bash 手册:

+(模式列表)

匹配给定模式的一次或多次出现。

模式列表是由“|”分隔的一个或多个模式的列表。

请参阅 Bash 手册:https://www.gnu.org/software/bash/manual/bash.html#Pattern-Matching

答案4

根据外壳的一些选项:

$ touch a akk aka
$ ksh -c 'echo a*(k)'
a akk
$ zsh -o kshglob -o nobareglobqual -c 'echo a*(k)'
a akk

nobareglobqual此处尾随(k)不被视为全局限定符)

$ bash -O extglob -c 'echo a*(k)'
a akk

$ zsh -o extendedglob -c 'echo ak#'
a akk

zsh's#相当于 regexp *

ksh93还可以在其 glob 中使用多种类型的正则表达式:

$ ksh93 -c 'echo ~(E:ak*)' # extended RE
a akk
$ ksh93 -c 'echo ~(P:ak*)' # perl-like RE
a akk
$ ksh93 -c 'echo ~(X:ak*)' # AT&T augmented RE
a akk
$ ksh93 -c 'echo @(~(E)ak*)' # alternative syntax
a akk

相关内容