重击的历史


11

Bash的“ globbing”和正则表达式为何不相同,是否有历史原因?例如,我相信Bash中的[1-2]*匹配项以1或2开头,后跟其他任何内容,而正则表达式[1-2]*仅匹配1和2的序列。我的Bash脚本和REGEX foo都非常薄弱,我经常遇到与这些差异相关的问题,这让我很好奇为什么它们不同。


3
您会考虑rm -- ^[^.].*\.txt$代替rm -- *.txt吗?
斯特凡Chazelas

1
您的许多Q都来自lwn:lwn.net/Articles/96687
slm

有一些对文件名进行操作并使用regexp的命令。例如,查找find . -regex ".*\.txt$" | xargs rm --rename重命名文件(sed用于文件名),请注意某些系统使用的不同rename
ctrl-alt-delor 2014年

@richard,我^[^.].*\.txt$要考虑对点文件的忽略。请注意,-regex是一个GNU扩展,有的像贝壳ksh93的或zsh中可以在自己的水珠结合正则表达式(试行例如:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
斯特凡Chazelas

2
这种重击非常谨慎地遵循了现有做法,同时避免了无法协调的不兼容的更改和扩展,这是其最大的优势之一。
ormaaj 2014年

Answers:


12

bash最初是在80年代后期设计的,是对kshcsh / tcsh的某些交互功能的部分克隆。

浮球的起源必须在它所建立的早期外壳中找到。

ksh本身是Bourne外壳的延伸。Bourne shell本身(于1979年在Unix V7中首次发布)从头开始是一个干净的实现,但是它并没有完全脱离Thompson shell(V1-> V6的外壳),并结合了Mashey shell的功能。

特别是,命令参数仍然由空格分隔,|现在是新的管道运算符,但^仍然受支持(并且也解释了为什么这样做[!a-z]而不是[^a-z]),$1仍然是脚本的第一个参数,反斜杠仍然是转义字符。因此,许多regexp运算符(^\|$)在shell中都有自己的特殊含义。

Thompson shell依赖于外部实用程序来进行通配。当sh发现不带引号的*[?■在命令,它会运行通过命令glob

rm *.txt

最终将glob运行为:

["glob", "rm", "*.txt"]

而glob最终将运行rm与该模式匹配的文件列表。

grep a.\*b *.txt

将运行glob为:

["glob", "grep", "a.\252b", "*.txt"]

*上述已经通过设置该字符的第8位,防止引述glob把它当作一个通配符。glob然后会在调用之前删除该位grep

要对正则表达式进行等效处理,那就是:

regexp rm '\.txt$'

要么:

regexp rm '^[^.].*\.txt$'

排除点文件。

需要避免将运算符用作shell特殊字符,因为.文件名中常见的regexp运算符使它不适合匹配文件名,并且对于初学者来说很复杂。在大多数情况下,您只需要通配符即可替换一个(?)或任意数量(*)的字符。

现在,不同的外壳添加了不同的全局操作符。如今,ksh和zsh glob(在某种程度上bash -O extglob实现了ksh glob的子集)在功能上等效于正则表达式,其语法在使用文件名和当前shell语法时不再那么麻烦。例如,在zsh(具有extensionglob扩展名)中,您可以执行以下操作:

echo a#.txt

如果您希望(不太可能)匹配由a后跟组成的文件名.txt。比echo (^a*\.txt$)(在这里使用花括号作为将regex运算符与shell运算符隔离的方法更容易),这可能是shell处理它的一种方式。

echo (foo|bar|<1-20>).(#i)mpg

对于基本名称为foo,bar或1到20的十进制数字的mpg文件(不区分大小写)...

ksh93现在还可以将regexp(基本的,扩展的,类似perl的或“增强的”)合并到其glob中(尽管它有很多bug),甚至还提供了在glob和regexp(printf %Rprintf %P)之间转换的工具:

echo ~(Ei:.*\.txt)

到比赛(非隐藏),TXT处理文件Ë xtended正则表达式,区分 nsensitively。


酷写!实际上,您不能使用~(opt:pat)任何大写的选项。也许吧print -r -- ~(Ei).*\.txt$。将模式放入内部似乎仅对避免必须为部分模式切换选项然后再将其关闭有用。奇怪的是,您可以在同一个glob中混合和匹配多种模式语言。~(Ki)*.~(E)txt$是等效的。(最后,所有内容都将转换为regex并在内部传递给libast的regex引擎)。
ormaaj 2014年

@ormaaj,~(Ei:.*\.txt)即使使用ksh93 o +之类的15岁版本也对我有用。
斯特凡Chazelas

我也可以使用其中一个保存的测试二进制文件(2014-12-24),但是我记得遇到了问题。当ksh仍在商业化开发时,总是在每个版本之间随意破坏和修复问题。我记得模式匹配代码是脆弱的领域之一。
ormaaj

@ormaaj ~(E)x和之间的区别~(E:x)是,后者是锚定的x仅在前者匹配包含的任何内容时才匹配x),这可能是您遇到的那种问题(用于~(-lr)~(E:x)删除锚定,~(E-lr:x)不会这样做)。无论如何,即使在最新版本中,我也认为这是错误的。
斯特凡Chazelas

9

正规语言Kleene在1956年引入的。开创性的论文没有完整的现代正则表达式符号,但确实引入了“ Kleen star”:A*意思是“任意重复A”。在接下来的十年中,出现了或多或少的标准符号,特别是.对于任意字符,?这意味着以前的字符是可选的。

Bash的glob表示法起源于1971年在Unix v1中引入的glob命令。当时,glob是由一个单独的程序执行的。后来被移入了外壳。早期命令必须指“任何一个字符”和“任何字符序列”。我不知道为什么选择角色;是非常直观的,并且可能是从正则表达式中获得灵感的。glob?*?*

混淆并不是要像正则表达式一样普遍,并且正则表达式在当时还不是很普及,因此没有要求统一这些概念。从一开始,有语法不兼容,用?.*意在文件名中的模式和正则表达式中不同的东西。

诸如bash之类的现代shell在glob模式上进行扩展,但是它是逐步发展的,保持了向后兼容性。Ksh88(1988年的Korn shell版本)引入了扩展的shell模式语法,该语法与通常的正则表达式不能相同,但是受到了它的强烈启发:它*(PATTERN)表示任意数量的重复PATTERN@(PATTERN1|PATTERN2)表示“ PATTERN1PATTERN2”,等等

如果您shopt -s extglob先发布,bash的现代版本(自2.02开始)支持ksh88的扩展模式。


Bash是否曾经不支持extglob?据我所知,Bash,zsh和{pd,m} ksh自早期以来就支持与ksh88手册中记录的完全相同的glob。到目前为止,Ksh甚至都没有禁用“扩展的” glob量词的选项,并且ksh93是其中仅有的一个扩展超过ksh88的扩展之一。
ormaaj 2014年

2
@ormaaj Ksh88扩展了glob,并extglob在1998年左右的bash 2.02中引入了该选项。Zsh ksh_glob在同一时间在3.1系列中获得了它。Zsh有许多自己的globing扩展(有些需要此extended_glob选项)。
吉尔斯(Gillles)“所以-别再邪恶了”

我知道了。因此,实际上已经来不及证明需要选择权了。(我认为默认情况下,默认情况下关闭这些天虽然没有意义,但是很有趣。)
ormaaj 2014年

1
@ormaaj,请注意bash,与相对ksh,extglob使bash与POSIX不兼容,因为它没有在变量中禁用。在中ksh,按POSIX的要求扩展到var='@(*)'; echo $var当前目录@()以POSIX 开头和结尾的所有文件名,而在bash -O extglob其中扩展为所有文件。(不过,人们可能会认为bash行为在这里更有意义(当您确实希望在变量中使用模式时,ksh行为会很痛苦))。由于(POSIX / Bourne兼容性),该glob语法太尴尬了。与zsh扩展glob进行比较。
斯特凡Chazelas

@StéphaneChazelas没错,我喜欢ksh对此有多精明。除非实际上仅限于POSIX,否则它很少发挥作用。几乎所有用于分词的用法都被更好的功能所取代,并且将模式存储在变量中无论如何都是极其麻烦的事情,因为您必须清空IFS,在除bash之外的所有位置都禁止大括号扩展。我认为使用存储模式完全安全仍然是不可能的。例如,这个古老的逃生问题从未真正解决过。
ormaaj 2014年

1

历史原因:是。参考:http :
//en.wikipedia.org/wiki/Glob_(programming)#Origin

只是为了展示差异,这是一个很好的示例: a*

  • shell globbing:意思是,第一个字符是a,然后是其他任何字符(a,ab,abca ...)
  • regex:含义是,字符a(a,aa,aaa ...)的零个或多个重复

我很容易同意这种含义上的差异对于新用户来说非常令人困惑。

对于新手来说,通配也许更容易掌握,但它的功能也不太强大。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.