bash shell 对引号的用法的解释是否不一致?

bash shell 对引号的用法的解释是否不一致?

这是我的代码,我在 2014 年中更新到最新版本的 Macbook Pro 上。我使用 Bash 5.1.8

apples-MacBook-Pro:Documents apple$ egrep s* states.txt
apples-MacBook-Pro:Documents apple$ egrep "s*" states.txt
Alabama
Alaska
Arizona
Arkansas
California
Colorado
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
Nebraska
Nevada
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming
apples-MacBook-Pro:Documents apple$ egrep s{2} states.txt
Massachusetts
Mississippi
Missouri
Tennessee
apples-MacBook-Pro:Documents apple$ egrep "s{2}" states.txt
Massachusetts
Mississippi
Missouri
Tennessee

如你所见,如果我不引用 s*,egrep 就不会解释元字符 *,(我假设它将 * 视为文字?)但如果我引用,它被当作元字符处理,正如预期的那样。然而,使用 {} 时情况并非如此,无论我是否引用正则表达式,它都会被 shell 解释为元字符。

为什么会有这种差异?

答案1

如您所见,如果我不引用 s*,egrep 就不会解释元字符 *,(我假设它将 * 视为文字?)但是如果我引用 s,它会被视为元字符,正如预期的那样

如果你引用s*,egrep 甚至不收到在命令执行之前,bash 会将元字符*作为通配符进行扩展——这是文件通配符在 Unix shell 中的通常工作方式。

由于您有一个与此通配符匹配的文件(完全相同的 states.txt),因此 bash 将运行的实际命令是。 (当然,如果有更多以“s”开头的文件,它们将作为附加参数包含在内。)egrep states.txt states.txt

仅当通配符匹配时文件,然后将其不加改变地传递给程序(例如,xnughxkrtb*可能保持原样)。您可以通过添加前缀来找出实际的命令echo- 因为通配符扩展是由 shell 完成的,所以它将同样为 echo 和 egrep 完成。

另一方面,如果你引用s*,egrep 会按照书写方式接收它。(虽然在 egrep 中它不是通配符而是正则表达式,它几乎匹配所有内容,因为任何字符串都有“零个或多个”'s' 字符,这就是它输出所有状态的原因。)

shell 也能识别\隐藏特殊字符,因此egrep s\* states.txt也能正常工作。(如果您希望 egrep 本身按字面意思接收反斜杠,则可能需要将其加倍。)

然而,使用 {} 时情况并非如此,无论我是否引用正则表达式,它都会被 shell 解释为元字符。

这是几乎相同的情况,{}是另一种类型的 shell 扩展。但是,在您的情况下,它仍然可以在不加引号的情况下工作,因为这种类型的 shell 扩展不会触发,除非它至少有两个逗号分隔的项(或一个范围)。也就是说,{a,b}{a..z}由 bash 扩展,但{a}单独使用则不会。

例如,如果你尝试s{2,5}不引用,这已被 shell 扩展,结果命令将是。(同样,您可以使用first 来检测这一点。)egrep s2 s5 states.txtecho

相关内容