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


543

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

bash: syntax error near unexpected token `{:'

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

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

它似乎始终在zsh中工作,但在Bash中不起作用。

一个相关的问题并不能解释有关空格的任何信息,这确实是我的问题。为什么Bash能够正确解析需要空格?


6
我在这里发布了相同的问题(不包括纹身部分)。
Benoit 2014年

3
另外,不能将冒号(:)用作函数名称(请参阅:pubs.opengroup.org/onlinepubs/9699919799/utilities/…)... FreeBSD的/ bin / sh甚至在此问题上也给出了错误...
Martin Tournoij 2014年

5
@Carpetsmoker:我不确定这有什么关系。这个问题是关于Bash的。
丹尼斯

Answers:


267

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

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

:(){ :|:&};:

35
简单的解决方案:将taoo的第一部分向左移动,然后在两部分之间移植皮肤。

23
我喜欢这个词,on the other hand...双关语意在吗?;):D(对不起,不支持主题评论。)
anishsane 2014年

4
但这与zsh不同吗?zsh有何不同?
tfogo 2014年

2
很好的解释,除了{和在此上下文中}shell关键字。只有由于缺少周围的空格/元字符而无法识别它们时,它们才被视为它们所包含的单词的字面部分。(然后是大括号扩展,发生在不同的上下文中。)
mklement0

2
@DmitriChubarov在命令名称中可以使用大括号(包括函数:{foo} () { echo hello; }。“名称”(按以下定义)bash:“仅由字母数字字符和下划线组成的单词,以字母字符或下划线开头”,仅适用于变量名。
chepner

82

只是纹身一个

#!/bin/zsh

射在上面,你会没事的。


6
如果我们很挑剔的话,shebang将根本无法工作,因为shell(希望是zsh)处于交互模式,如提示符所示……
SzG 2014年

50

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

(ls)

哪个有效,并且:

{ls}

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

{ ls; }

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

您所要做的就是告诉人们您使用的是比例字体,并且具有相当窄的空格字符。


12
@DmitriChubarov-这是一个非常狡猾的把戏,使用了完全不同的花括号含义。它扩展了逗号分隔的值列表,在这种情况下,它只是ls
彼得·韦斯特莱克

7
但是……男孩……您将在余生中拥有纹身!您一直将自己标记为书呆子!而且那么你甚至不能正确的有它缝合之前得到它?我想这超出了书呆子的两步;-)没有冒犯,伙计,我只是想知道。
阿尔夫,2014年

14
@Alfe在纹身之前尝试过它,但是我在zsh中尝试过它,我认为它的解析与bash相同。我很愚蠢,但我只是告诉人们这是zsh。:)
spydon 2014年

20
@spydon或您告诉他们您故意留出了空间,以使从纹身中复制命令的人们不会意外运行该命令并使其机器崩溃;)

4
嘿,如果它在zsh中有效,为什么不直接在它上面(或前面)添加#!/ bin / zsh?无论如何,最好先指定外壳。
亚当·米勒

41

尽管在tatoo字体中不容易看到,但实际上在花括号和冒号之间有一个字节顺序标记(BOM)(当您收到tatoo时您可能已经被陶醉了,您没有注意到它,但是它确实存在) 。这留下了三个明显的可能性:

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

40

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

这是因为外壳解析的方式。函数定义开始后(即)后需要一个空格{

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

是有效的。另一方面,

foo() {echo hey&}

不是。


您实际上需要这样的纹身:

在此处输入图片说明


来源

  /* 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在到达所需的大括号之前就遇到了调用的命令?
乔纳
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.