从让 bash 使用外部 `time` 命令而不是 shell 内置命令,斯特凡·查泽拉斯写道:
没有
time
内置的 bash。time
是一个关键字,所以你可以这样做time { foo; bar; }
我们可以验证一下:
$ type -a time
time is a shell keyword
time is /usr/bin/time
它没有表明这time
可以是内置命令。
“关键字”的定义是什么?
“关键字”与 Bash 参考手册中的“保留字”是同一概念吗?
保留字
这个词对 shell 有特殊的意义。大多数保留字引入 shell 流控制结构,例如
for
和while
。关键字是否一定不是命令(或者不是内置命令)?
作为关键字,不是
time
一个命令(或者不是一个内置命令)?根据关键字和内置的定义,为什么不是
time
内置而是关键字?为什么“你可以做
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
。或while
或case
等等。
答案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
, 、Do
和Done
实际上是应该被词法分析器映射和识别的标记:
%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 扩展。