为什么元字符周围有时需要空格?

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

bash: syntax error near unexpected token `{:'

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

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

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

一个相关的问题没有解释任何关于空白的内容,这正是我的问题所在;# EYZ1

80751 次浏览

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

(ls)

这是可行的,并且:

{ls}

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

{ ls; }

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

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

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

这是因为壳层的解析方式。你需要在函数定义开始后,也就是在{之后,有一个空格。

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

是有效的。另一方面,

foo() {echo hey&}

不是。


你需要一个这样的纹身:

enter image description here


:

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

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


等价形式的

:(){ :|:& };:

:(){
:|:& };:

注意,在替代版本中,{后面没有空格,但是换行会使shell将{识别为令牌。

在BASH中有一个分隔令牌的字符列表。这些字符被称为元字符,它们是|&;()<>&0和&1。另一方面,大括号({})只是组成单词的普通字符。

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

:(){ :|:&};:

虽然在纹身字体中不容易看到,但在大括号和冒号之间实际上有一个字节顺序标记(BOM)(你可能在纹身时已经足够陶醉了,没有注意到它,但它确实存在)。这留下了三种明显的可能性:

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

只要纹身

#!/bin/zsh

把它放在上面,你就没事了。