关于 bash shell 似乎存在一些我无法理解的不一致之处。
如果我执行:
ls;date;time
三个查询的结果按顺序显示。
但是,在交换日期和时间位置时,会弹出一条错误消息。
因此如果我执行:
ls;time;date
错误信息显示:bash: syntax error near unexpected token 'date'
。
有人能解释一下吗?
答案1
管道中的命令time
不是/usr/bin/time
二进制文件,而是 bashtime
内置的。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 的保留字。
答案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
内置函数在 stdout 上生成的任何内容。但由于time
它本身不会向 stdout 写入任何内容,因此它似乎可以工作。
最后,据指出,这是有效的:
time ; ; date
遗憾的是我无法解释:)