关于bash:为什么元字符周围有时需要空格?

Why is whitespace sometimes needed around metacharacters?

几个月前,我在手臂上纹了一个叉形炸弹,我跳过了空白,因为没有它们我觉得它看起来更好。但令我沮丧的是,有时(不总是)当我在一个外壳里运行它时,它不会启动一个分叉炸弹,但它只是给出了一个语法错误。

1
bash: syntax error near unexpected token `{:'

昨天,我试着在朋友的弹壳里运行它,然后加上空白,它突然工作了,用:(){ :|:& };:代替:(){:|:&};:

空白有关系吗?我手臂上纹了语法错误吗?!

它似乎总是在zsh中工作,但在bash中不工作。

一个相关的问题不能解释关于空白的任何东西,这确实是我的问题;为什么bash需要空白来正确地解析它?


在bash中有一个分隔令牌的字符列表。这些字符称为元字符,分别是|&;()<>、空格和制表符。另一方面,大括号({}只是组成单词的普通字符。

}之前省略第二个空格就行了,因为&是一个元字符。因此,您的纹身应该至少有一个空格字符。

1
:(){ :|:&};:


只是纹身

1
#!/bin/zsh

她在上面,你会没事的。


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

1
(ls)

哪些有效,以及:

1
{ls}

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

1
{ ls; }

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

你所要做的就是告诉人们你使用的是一种比例字体,它有一个相当窄的空格字符。


虽然在塔图字体中不容易看到,但括号和冒号之间实际上有一个字节顺序标记(bom)(当你得到塔图时,你可能已经喝得醉透了,但你没有注意到它,但它确实存在)。这留下了三个明显的可能性:

  • 当您转录代码时,您未能输入BOM。结果表明,该方法具有很好的应用前景。shell根本不识别在失败的转录中不存在的bom。
  • 你的壳太旧了。它不识别unicode字符,所以bom(以及可能所有其他unicode字符)被完全忽略,即使bom在除文件开头之外的任何位置都被视为零宽度、不间断的空格。
  • 你的外壳太新了。不赞成将BOM用作zwnbs,作者已经实现了以后的Unicode版本,在该版本中不再允许使用这种用法。

  • and then I added the whitespace and it suddenly worked ...

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

    1
    2
    3
    foo() { echo hey& }
    foo() { echo hey&}
    foo(){ echo hey&}

    是有效的。另一方面,

    1
    foo() {echo hey&}

    不是。

    你实际上需要这样的塔图:

    enter image description here

    来源:

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

    {后面省略一个空格会导致{echo被解释为单个令牌。

    等价形式

    1
    :(){ :|:& };:

    将是

    1
    2
    :(){
    :|:& };:

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