【问题标题】:Why is whitespace sometimes needed around metacharacters?为什么有时元字符周围需要空格?
【发布时间】:2014-02-06 19:58:20
【问题描述】:

几个月前,我在手臂上纹了一个fork bomb,我跳过了空格,因为我觉得没有它们看起来更好看。但令我沮丧的是,有时(并非总是)当我在 shell 中运行它时,它不会启动 fork 炸弹,而只会给出语法错误。

bash: syntax error near unexpected token `{:'

昨天我尝试在朋友的Bash shell 中运行它时发生了这种情况,然后我添加了空格,它突然起作用了,:(){ :|:& };: 而不是:(){:|:&};:

空格重要吗?我在手臂上纹了语法错误吗?!

它似乎总是在 zsh 中工作,但在 Bash 中却不行。

A related question 没有解释任何关于空格的内容,这确实是我的问题; 为什么 Bash 需要空格才能正确解析它?

【问题讨论】:

  • 我发了同样的问题here(纹身部分除外)。
  • 另外,冒号 (:) 不能用作函数名(请参阅:pubs.opengroup.org/onlinepubs/9699919799/utilities/…)... FreeBSD 的 /bin/sh 甚至对此给出了错误...跨度>
  • @Carpetsmoker:我不确定这有什么关系。这个问题是关于 Bash 的。

标签: bash shell syntax syntax-error


【解决方案1】:

大括号更像是奇怪的关键字而不是特殊符号,并且确实需要空格。例如,这与括号不同。比较:

(ls)

哪个有效,并且:

{ls}

查找名为{ls} 的命令。要工作,它必须是:

{ ls; }

分号停止将右大括号作为ls 的参数。

您所要做的就是告诉人们您使用的是比例字体和一个相当窄的空格字符。

【讨论】:

  • @DmitriChubarov - 这是一个非常狡猾的把戏,使用了完全不同的大括号含义。它扩展了以逗号分隔的值列表,在本例中就是 ls
  • 但是……男孩……你的余生都会有纹身!你一直把自己标记为书呆子! 那么你甚至无法在缝合之前把它弄好?我猜这比书呆子还要两步 ;-) 无意冒犯,朋友,我只是想知道。
  • @Alfe 我在纹身之前尝试过,但是我在我的zsh中尝试过,我认为它的解析与bash相同。我傻了,但我只会告诉人们它是zsh。 :)
  • @spydon 或者你告诉他们你故意留下了空间,这样人们从你的纹身中复制命令就不会意外运行它并导致他们的机器崩溃;)
  • 嘿,如果它在 zsh 中有效,为什么不在它的正上方(或之前)添加 #!/bin/zsh 呢?无论如何,最好先指定 shell。
【解决方案2】:

然后我添加了空格,它突然起作用了......

这是因为 shell 的解析方式。在函数定义开始后需要一个空格,即{ 之后。

foo() { echo hey& }
foo() { echo hey&}
foo(){ echo hey&}

有效。另一方面,

foo() {echo hey&}

不是。


你真的需要这样的纹身:​​p>


来自source

  /* We ignore an open brace surrounded by whitespace, and also
     an open brace followed immediately by a close brace preceded
     by whitespace.  */

{ 之后省略一个空格会导致{echo 被解释为单个标记。


等价形式

:(){ :|:& };:

:(){
:|:& };:

请注意,备用版本中{ 之后没有空格,但换行符会导致 shell 将 { 识别为标记。

【讨论】:

  • “在 { 之后省略一个空格会导致 {echo 被解释为单个标记。” -- 那么解析器是否认为它在到达所需的左大括号之前遇到了一个名为{echo 的命令?
  • 哈哈。那张照片,恰好是我的脖子:)
【解决方案3】:

在 BASH 中有一个分隔标记的字符列表。这些字符称为元字符,它们是|&;()<>空格标签。另一方面,花括号({})只是组成单词的普通字符。

} 之前省略第二个空格也可以,因为& 是一个元字符。因此,你的纹身应该至少有一个空格字符。

:(){ :|:&};:

【讨论】:

  • 简单的解决方法:将taoo的第一部分向左移动并在两部分之间移植皮肤。
  • 我喜欢这个词,on the other hand... 双关语? ;) :D(对不起,偏离主题的评论。)
  • 但这对于 zsh 有什么不同? zsh 有什么不同?
  • 很好的解释,除了 {} 在这个上下文中是 shell 关键字。只有当它们没有被这样识别时——由于缺少周围的空格/元字符——它们才会被视为它们成为的单词的字面部分。 (然后是大括号扩展,它发生在不同的上下文中。)
  • @DmitriChubarov 命令名称中允许使用大括号(包括函数:{foo} () { echo hello; }。“名称”,在 bash 中定义为“仅由字母数字字符和下划线组成的单词,并以字母字符或下划线”,仅适用于变量名。
【解决方案4】:

虽然在纹身字体中不容易看到,但在大括号和冒号之间实际上有一个字节顺序标记 (BOM)真的在那里)。这留下了三个明显的可能性:

  1. 您在转录代码时未能输入 BOM。结果是GIGO的明显应用。 Shell 根本无法识别失败转录中不存在的 BOM。
  2. 您的外壳太旧了。它不识别 Unicode 字符,因此 BOM(可能还有所有其他 Unicode 字符)被完全忽略,即使除了文件开头之外的任何地方的 BOM 都应该被视为零宽度、不间断的空间.
  3. 你的外壳太新了。不推荐使用 BOM 作为 ZWNBS,作者已经实现了 Unicode 的未来版本,其中不再允许这种用法。

【讨论】:

    【解决方案5】:

    纹身一个

    #!/bin/zsh
    

    shebang 在它上面,你会没事的。

    【讨论】:

    • 如果我们很挑剔,shebang 将根本不起作用,因为 shell(希望是 zsh)处于交互模式,提示符可以证明...
    猜你喜欢
    • 2023-03-13
    • 2013-04-07
    • 2016-05-10
    • 2018-01-05
    • 2019-04-17
    相关资源
    最近更新 更多