ChatGPT解决这个技术问题 Extra ChatGPT

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

几个月前,我在手臂上纹了一个 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 的。

T
Toothbrush

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

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

:(){ :|:&};:

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

只纹一个

#!/bin/zsh

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


如果我们很挑剔,那么 shebang 根本不起作用,因为 shell(希望是 zsh)处于交互模式,提示符证明了这一点......
C
Charles Duffy

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

(ls)

哪个有效,并且:

{ls}

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

{ ls; }

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

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


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

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

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


B
Benjamin W.

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

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

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

是有效的。另一方面,

foo() {echo hey&}

不是。

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

https://i.stack.imgur.com/w2Dmj.png

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 的命令?
哈哈。那张照片,恰好是我的脖子:)