关键字、保留字和内置之间的区别?

关键字、保留字和内置之间的区别?

让 bash 使用外部 `time` 命令而不是 shell 内置命令,斯特凡·查泽拉斯写道:

没有time内置的 bash。time是一个关键字,所以你可以这样做time { foo; bar; }

我们可以验证一下:

$ type -a time
time is a shell keyword
time is /usr/bin/time

它没有表明这time可以是内置命令。

  1. “关键字”的定义是什么?

  2. “关键字”与 Bash 参考手册中的“保留字”是同一概念吗?

    保留字

    这个词对 shell 有特殊的意义。大多数保留字引入 shell 流控制结构,例如forwhile

  3. 关键字是否一定不是命令(或者不是内置命令)?

    作为关键字,不是time一个命令(或者不是一个内置命令)?

    根据关键字和内置的定义,为什么不是time 内置而是关键字?

  4. 为什么“你可以做time { foo; bar; }”,因为“time是一个关键字”?

答案1

关键字、保留字和内置命令都是简单命令的“第一个词”。它们可以分为两组:关键字和内置函数。两者是互相排斥的。单词(标记)可以是关键字或内置单词,但不能同时是两者。

为什么是“第一个字”

来自“简单命令”的 POSIX 定义(强调我的):

“简单命令”是一系列可选的变量分配和重定向,可以任意顺序,可选地后跟单词和重定向,并由控制运算符终止。

2.- 不是变量赋值或重定向的词应被扩展。如果任何字段在扩展后仍然存在,则第一个字段应被视为命令名称其余字段是命令的参数。

在识别出“第一个单词”并且扩展它之后(例如,通过别名),最终的单词是“命令”,每行中只能有一个命令。该命令字可以是内置命令或关键字。

关键词

是的,关键字是“保留字”。加载“man bash”并搜索关键字或执行此命令:LESS=+/'keyword' man bash

搜索中的第一个点击是这样的:

关键字 Shell 保留字。

它发生在完成部分,但非常清晰。

保留字

在 POSIX 中,有“保留字”的定义还有一些保留字作用的描述

但 Bash 手册有更好的工作定义。搜索“保留字”( LESS=+/'RESERVED WORDS' man bash) 并找到:

保留字 保留字是对 shell 有特殊含义的字。以下单词在未加引号且简单命令的第一个单词或 case 或 for 命令的第三个单词时被识别为保留:

! case do done elif else esac fi for function if in select then until while { } time [[ ]]

内置

Bash 手册中没有定义它,但它非常简单:

它是在 shell 内部实现的命令,用于满足 shell 的基本需求(cd、pwd、eval)或一般速度或避免在某些情况下与外部实用程序的解释发生冲突。

时间是一个关键词

为什么时间不是内置的而是关键字?

允许命令作为第二个词存在。

if ... then .... fi这与允许在第一个关键字之后包含命令(甚至复合命令)的方式类似if。或whilecase等等。

答案2

Q1、Q2

关键字的定义是什么?

“关键字”与 Bash 参考手册中的“保留字”是同一概念吗?

基本上,特殊词对句法结构很重要。 C 语言中有goto, if, while,enum等等;在 bash 中你有if, while(这些听起来很熟悉..),time等等。

是的,它们是相同的。

我在解释这个问题时有一定的自由度,因为 POSIX shell 和 bash 的基本语法元素是相似的。那么让我们看一下中的定义POSIX.1:2013 Shell 命令语言:

2.4保留字

保留字是对 shell 有特殊含义的字;看外壳命令。以下字应被视为保留字:

...

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

...

语法见外壳语法

让我们看一下 POSIX 语法,看看特殊词(现在是词法分析后的语法标记)是如何起作用的:

for_clause       : For name linebreak                            do_group
                 | For name linebreak in          sequential_sep do_group
                 | For name linebreak in wordlist sequential_sep do_group
/* ... */
do_group         : Do compound_list Done           /* Apply rule 6 */

这看起来很熟悉,对吧?请注意For, 、DoDone实际上是应该被词法分析器映射和识别的标记:

%token  If    Then    Else    Elif    Fi    Do    Done
/*      'if'  'then'  'else'  'elif'  'fi'  'do'  'done'   */


%token  Case    Esac    While    Until    For
/*      'case'  'esac'  'while'  'until'  'for'   */

/* and 'In' too -- They made a mistake! */
%token  In    /*      'in'   */

如果您听说过雅克或者野牛(或者,jison),这就是人们使用语法的方式。通过这些解析器生成器,它们可以生成一些东西来找出给定的输入“标记”流所使用的语法的哪些部分。

第三季度

关键字是否一定不是命令(或者不是内置命令)?

作为关键字,不是time一个命令(或者不是一个内置命令)?

没有一个关键字被视为命令。但是当然,您可以使用同名的命令/函数,例如:

# make a command to avoid command-not-found for `FOO=BAR time cmd`
time(){ time "$@"; }

根据关键字和内置函数的定义,为什么时间不是内置函数而是关键字?

因为就是这样人们决定做到:

// Licensed under GPLv2, bash:parse.y
// Copyright (C) 1989-2012 Free Software Foundation, Inc.
pipeline_command: pipeline
                | BANG pipeline_command
                | timespec pipeline_command
                | timespec list_terminator
                | BANG list_terminator;
pipeline        : pipeline '|' newline_list pipeline
                | pipeline BAR_AND newline_list pipeline
                | command;
timespec        : TIME | TIME TIMEOPT | TIME TIMEOPT TIMEIGN;

他们从中获得额外的力量(见下一个问题)。

第四季度

为什么“你可以做time { foo; bar; }”,因为“time是一个关键字”?

作为语法的一部分,人们自然可以让解析器处理一切,并做出像允许time在复合命令之前这样的决定。如果time仅作为命令实现,您将收到此类构造的语法错误(尝试echo { foo; bar; }),因为它实际上是使用“通常”规则进行解析的。

也想想[[。如果[[不是关键字,则构造 like[[ ($a == 2) || ($b != 3) ]]将使 shell 找到杂散的括号并抱怨。 (替换[[[并查看)。

PStime是一个公用事业而不是 POSIX 中的关键字,尽管后者仍然被认为是可以接受的。整个 time-a-trunk-of-commands 是 ksh 和 bash 扩展。

相关内容