为什么顺序在执行这些bash命令时很重要?


10

关于bash shell,我似乎无法理解某些不一致之处。

如果我执行:

ls;date;time

这三个查询的结果按顺序显示。

但是,在日期和时间位置互换时,会弹出错误消息。

所以如果我执行:

ls;time;date

错误消息显示:bash: syntax error near unexpected token 'date'

有人可以解释吗?


你的问题就出在time;dateVS date;time。这似乎是管道输入bashtime输出生成的最后一个char 的问题。在不同的终端仿真器中测试的结果是:-[Bash] $ date; time#[OK] $ time; date#[ NotOK ] bash:语法错误,在意外标记`date'$ time#附近,仅出现错误,表明它不是任何日期的结果。-[Csh] $日期;时间#[OK] $时间;日期#[OK]-[Tcsh] $日期;时间#[OK] $时间;日期#[OK]-[Ksh] $日期;时间#[ OK] $时间;日期#[OK]
Mostafa Shahverdy

我已经用错误消息的解释更新了答案。请检查这是否是您要找的答案。
zwets

Answers:


10

time管道中的命令不是/usr/bin/time二进制文件,而是time内置的bash 。man time与比较help time。您看到的错误是bash无法解析time参数。它必须存在或为换行符。它在您的第一个示例中是换行符,但在第二个示例中不存在。

另一方面,如果您要跑步

ls;date;'time'

要么

ls;'time';date

如果周围的引号'time'取消了其作为保留字的状态,那么bash解析该行就没有问题。现在,它解析列表中的三个命令,依次执行,并/usr/bin/time在两种情况下都报告使用错误。

附录

据观察,尽管time ; date产生错误,time ; ; date但不会产生错误。可能的解释是time ;bash 将其解释为等效于time <newline>。表达time ; ; date然后被解析为列表time ;date

这与观察到一致的time ;time ; ;有法律为好,解析为单身列表中的第二个是包含time ;随后列出了允许后可选的分号。

因此,另一种解释为什么会time ; date产生错误的方法bash: syntax error near unexpected token 'date'是,time使用分号将其与分开date。它只能这样做,因为time它是bash保留字。


谢谢你的解释!但是话又说回来,这种行为对我来说似乎是个错误:time应该允许使用NULL命令,而分号应该对列表进行定界,因此IMO time命令不应在其后“使用”分号。其他内置命令(可以带参数)不表现出这种行为。

@arrange复杂的是,时间不允许空命令(这会消除所有歧义),只允许使用换行符代替命令。所以time;date的确是任何解释语法错误。但是 time ;time ; ;这也将是非法的。它可以进行辩论是否time的行为是错误或仅仅是无证(这内部一致),但bug报告肯定会到位。您愿意提出吗?
zwets

好吧,我查看了源代码(bash4.2:parse.y:lines 1205-1221),上面说了这个time by itself can time a null command,然后由这样做$$ = make_simple_command (x, (COMMAND *)NULL);。至于提交错误,我不确定8)

应该注意的是,此问题是特定于bash的。这样time ; date的作品ksh93,并mksh没有任何错误,即使kshtime关键字。
Sergiy Kolodyazhnyy

2

time当解析命令行时,Bash将内置作为特殊情况处理。

在bash联机帮助页中可以看到,首先将键入的行拆分为一个列表:

pipeline ; pipeline

管道在哪里:

[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

或者在我们的情况下,只需:

time command

即,如果时间存在,则命令必须也存在。

[有一种特殊情况,允许time在其后加上换行符,但不适用于此处]

因此,在我们的案例中,我们有:

time;date

被分为两个管道:

1. time
2. date

流水线1的格式不正确,因为我们time没有命令。因此,错误。

请注意,命令行在time这里也不起作用:

$ /usr/bin/time;date
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]

bash按预期将其解析为2条管道:

1. /usr/bin/time
2. date

并且/usr/bin/time随后拒绝不带参数运行。请注意,这是错误而/usr/bin/time不是bash的错误。

反跳标记起作用的原因是反跳标记不再time被解释为管道中的特殊元素。

即与反-:

`time`;date

它被解析为两个管道:

1. `time`
2. date

请记住,就我们而言,管道是:

[time] command

最初的问题是我们time没有命令,这是不允许的。但是现在我们只需执行以下命令:

`time`

不带前命令time,因为反引号意味着将time其解释为命令,而不是前单词。

因此,bash然后time不带参数运行其内置函数,这是可以接受的。它不产生任何输出,并且我们看不到任何错误。

注意:

`time`

实际运行结果time内置,即它运行无论time内置的产生在标准输出上。但是由于time它本身不会向stdout写入任何内容,因此它似乎可以工作。

最后,需要注意的是:

time ; ; date

不幸的是,我无法解释:)


我认为您的解释更好,但对我来说仍然很奇怪。;date给定bash: syntax error near unexpected token ;,但是time ;date给定bash: syntax error near unexpected token date,因此bash在内置时间之后似乎不将命令视为“; date”。有趣的是,time ; ; date作品。

是的,谢谢@arrange,这很奇怪。我会稍作更新。
cdmackay 2013年

好的,@ arrange,已重写。仍然无法解释你的最后一个……叹息。
cdmackay 2013年

@cdmackay您正在混合反引号和引号。通过引用 'time'它失去了它作为保留字的含义。反引号使它在子shell中执行,该子shell的输出被拼接到命令中。这与讨论无关。事实上,您的示例`time\';date证明了与您的主张相反的事实:由于需要论证,因此您的推理应该会出错/usr/bin/time。之所以没有,是因为在执行它的子shell中,它time再次是保留字。
zwets

@arrange两者都是语法错误,并且都被报告在同一位置附近,因此我看不到那里的不一致之处。一旦它进入语法错误区域,就不能期望解析器知道其出路。如果需要解析器,则解析器不仅必须知道合法语法,而且必须知道每种可能的非法构造的语法,这在定义上是不可能的。
zwets
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.