{ 是保留字

{ 是保留字

长话短说: 为什么 POSIX 大括号组在保留字后需要空格{,而 subshel​​l 在保留字后不需要空格(

POSIX shell 语法定义大括号组和子 shell 如下

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

现在,如果我们从字面上理解,空格很重要。这意味着必须有空间来描绘左大括号和右大括号以及圆括号,如下所示

{ echo hello world; }

( echo hello world )

这也符合复合命令定义:

这些复合命令中的每一个在开头都有一个保留字或控制运算符,在末尾有一个相应的终止符保留字或运算符。

然而,没有意义的是为什么(list)and( list )工作得很好((不需要后面的空格),但是大括号扩展必须有一个前导空格,即{echo hello;}不起作用。

当然,保留字被视为外壳字是有意义的,后面需要一个空格来与概念保持一致场分裂,但是定义本身没有提及空格。此外,如果复合命令的 POSIX 定义将{(都视为保留字,为什么它们在这些保留字之后的空格字符方面会受到不同的处理?现在,克什(1)手册确实指出:

单词是字符序列,由不带引号的空白字符(空格、制表符和换行符)或元字符(<、>、|、;、&、( 和 ))分隔

换句话说,ksh 将识别(为单词分隔符是有意义的,其中第一个单词是命令或变量赋值。然而,POSIX 似乎没有提及(元字符。就 POSIX 语法而言,我发现的唯一可能的解释是{被视为“令牌”,而 as(未列为其中之一。

/* These are reserved words, not operator tokens, and are
   recognized when reserved words are recognized. */


%token  Lbrace    Rbrace    Bang
/*      '{'       '}'       '!'   */

那么造成这种差异的精确原因是什么?

接受的答复注释:

  • 将接受的复选标记移至艾萨克的回答因为它提供了 q引用形成标准它本身直接解决了我的问题:

    例如,“(”和“)”是控制运算符,因此<space>(list)中不需要。但是,“{”和“}”是 { list;} 中的保留字,因此在这种情况下需要前导<space>和。<semicolon>

  • 接受拘萨罗南达的回答。库萨拉南达的回答满足了我的需要,尽管主要是从非正式和直观的角度出发;它指出{is 是保留字和(is 运算符。 Michael Homer 在评论中也指出了同样的情况 - 复合命令定义指出(强调):

    这些复合命令中的每一个都有一个保留字或控制操作员一开始

  • {被定义为保留字,类似于Shell Grammar 中列出的foror while(请参阅问题中的最后一个代码块)

  • 第 2.9 节规定(强调):

    特别是,这些表示包括标记之间的间距在某些<blank>不需要 s 的地方(当标记之一是运算符时)。

  • 虽然标准没有明确定义(运算符,(但简称为运算符;具体来说,第2.9.2节

    如果管道以保留字开始!并且command1是一个子shell命令,应用程序应确保command1开头的(运算符与!分隔一个或多个字符。紧跟在(运算符后面的保留字!的行为是未指定的。

  • 关于堆栈溢出的问题Digital Trauma 指出第 2.4 节有关保留字的内容:

    仅当没有引用任何字符并且该单词用作以下内容时,才会发生这种识别:

    -命令的第一个词

  • 正如 Kusalananda 的回答中提到的“POSIX 语法中显示的空格不是 shell 输入数据中需要存在的空格,而只是显示语法本身的一种方式。事实上,大括号是保留字,这意味着它们必须被空白包围”正如所提到的迈克尔·霍默在评论中:“如果这些空格本身就很重要,那么它们需要列在生产

案件结案。

答案1

大括号和括号之间的区别在于,大括号(和!)是保留字,就像for、等ifthen而括号是控制运算符。单词需要用空格分隔。

这意味着就像你不能拥有

foriin*; do

你不能拥有

{somecommand;} >file

或者

if !somecommand; then

POSIX 语法中显示的空格并不是 shell 输入数据中需要存在的空格,而只是显示语法本身的一种方式。事实上,大括号是保留的这意味着它们必须被空格包围,而子 shell 的括号则不需要。

答案2

这是 shell 将行分成标记的方式的限制。

外壳上写着线从输入文件和根据第2节“Shell简介”将它们转换为单词或一个操作员:

  1. shell 将输入分解为标记:单词和运算符

{ 是保留字

有些词是保留字

保留字是对 shell 有特殊含义的字。以下字应被视为保留字:

! { } case do done elif else esac fi for if in then until while

文字,被识别为文字,必须是分隔的

保留字仅在分隔时才会被识别...

大多由空格组成(第 7 点)和由运营商。

  1. 如果当前字符是不带引号的 <blank>,则包含前一个字符的任何标记都会被分隔,并且当前字符将被丢弃。

( 是一个运算符

运营商自己站着:

而运算符本身就是分隔符。

在哪里“运营商”是:

3.260 操作员

在 shell 命令语言中,要么控制操作员或重定向操作员。

重定向运算符是:

重定向运算符

在 shell 命令语言中,执行重定向功能的令牌。它是以下符号之一:

<     >     >|     <<     >>     <&     >&     <<-     <>

控制运算符是:

3.113 控制操作符

在 shell 命令语言中,执行控制功能的标记。它是以下符号之一:

&   &&   (   )   ;   ;;   newline   |   ||

结论

因此,“(”和“)”是控制运算符,而“{”“}”是保留字。

和完全相同的描述你的问题在规范内:

例如,“(”和“)”是控制运算符,因此(list)中不需要<space>。但是,“{”和“}”是 { list;} 中的保留字,因此在这种情况下需要前导 <space> 和 <semicolon>。

这准确地解释了为什么在{.

这是有效的:

{ echo yes;}

就像这样:

{(echo yes);}

这:

{(echo yes)}

甚至是这个:

{>/dev/tty echo yes;}

相关内容