通配符作为 shell 参数

Wildcards as shell parameters

我知道正则表达式和通配符的一般工作原理,但我不太明白为什么可以将它们用作参数。

ls /[!\(][!\(][!\(]/

命令产生以下输出

...
com.apple.launchd.AIPZ6SAfpO
com.apple.launchd.HarlOx3LWS
com.apple.launchd.VmTi5KDz1h
powerlog

/usr/:
X11     include     libexec     sbin        standalone
bin     lib     local       share

/var/:
agentx      empty       log     netboot     rwho
at      folders     ma      networkd    spool
audit       install     mail        root        tmp
backups     jabberd     msgs        rpc     vm
db      lib     mysql       run     yp

根据我的理解,这应该匹配每三个字符的文件夹名称,不包含斜杠 /[!\(][!\(][!\(]/

但是为什么我可以用它作为参数呢?

您不能使用正则表达式作为参数(或者更确切地说,shell 将字符串放在参数中时不会将其视为正则表达式)。 unquoted glob /[!\(][!\(][!\(]/ 匹配,顺序为:

  1. 一个斜杠。
  2. 三个不是起始括号的字符。
  3. 一个斜杠。

换句话说,三个字母的根目录在任何地方都不包含 (


shell glob 扩展为零(例如,在 Bash 的 nullglob 的情况下)或更多可以传递给 execve,在这个命令中:

$ strace -fe execve echo *
execve("/usr/bin/echo", ["echo", "directory1", "directory2"], 0x7ffcff705ce8 /* 44 vars */) = 0

因为 shell 就是这样工作的。任何包含(未加引号的)glob characters/expressions 的参数都将扩展为文件名。这就是 rm *.txt 中发生的事情(因为 * 是一个 glob 字符),这就是 ls /[!\(][!\(][!\(]/ 中发生的事情(因为 [abc] 是一个 glob 表达式)。

不过,它们不是正则表达式。参见例如https://mywiki.wooledge.org/glob 语法。

不,你不知道.... shell 模式在 glob(3) 中描述,而正则表达式(更详细的概念)在 regex(3) 中描述 两个不同的库用于类似目的。 sh(1) 在替换参数时根本不使用正则表达式。它仅使用 glob(3) 库。