`\time`、`t\ime` 和 `\cd` 实际上是做什么的?(shell 中的反斜杠很有趣)

Jon*_*fer 9 shell posix quoting time-utility

虽然讨论过之间的差异/usr/bin/time,并内置在外壳(bash和zsh中)time,有人提到可以使用\time作为简写来获得/usr/bin/time

起初,这似乎是一个很好的无辜捷径,但随后出现了一些问题:

  • 为什么也t\ime有效?
  • 为什么要\cd更改目录,即使/usr/bin/cd¹ 没有?

所以很明显,\foo不等价于$(which foo)。现在的问题是:

\foo在 bash 和 zsh 中观察到的行为是否以任何方式被 shell 的 POSIX 定义所涵盖,如果是,为什么它的行为如此?


脚注 1:/usr/bin/cd是,在我的系统上,

#!/bin/sh
builtin cd "$@"
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 14

t\imeor \cd(或"tim"eor'cd'${-##*}timeor${-+time}以及您能想到的所有其他引用和扩展组合最终会解析为timeor cd),是:另一种写法cdtime.

但是,这最终会解决cdtime稍后解决shell 语法解析和解释。特别是,这种情况发生在 shell 关键字识别和别名替换发生很久之后。

因此,当 shell 在其语言中寻找关键字时,它不会识别ti\metimeshell 关键字。所以一个:

ti\me echo test
Run Code Online (Sandbox Code Playgroud)

将被 shell 识别为一个简单的命令,而不是time后跟一个简单命令的关键字。

然后ti\me将处理引用(这里反斜杠引用m不需要引用的字符,引用字符被删除,你得到time)并且一个time 命令将像任何其他命令一样被查找(在内置命令列表中) , 中的函数和可执行文件$PATH。很可能会在/bin/time这里)

对于cdcdshell 语言中没有关键字,只有一个cd内置命令(优先于您的/usr/bin/cd)。但是,如果您确实为cd(like alias cd=pushd)定义了别名,则再次相同。由于别名替换很早就完成了,在删除引号之前,如果您有一个别名 forcd而不是一个 for \cd(请注意,没有多少 shell 允许别名中带有反斜杠),然后通过编写:

\cd dir
Run Code Online (Sandbox Code Playgroud)

你确保你的cd别名没有被替换。

简而言之,引用命令名称或其任何部分可防止其被视为 shell 关键字(诸如while, for, if, {... 之类time的关键字仅在某些shell 中是关键字),并绕过您可能拥有的别名.

但是,它不会强制该命令解析为 中的可执行文件$PATH,该命令仍然首先在函数(您可以通过执行来解决command time cmd...)和内置函数(您可以通过执行来解决env time cmd...,尽管我不知道)中搜索具有内置time命令的外壳)。

请注意,在某些 shell 中,引用也会影响typeset/ declare/ export/ local... 系列的特殊内置函数的行为。请参阅局部变量赋值是否需要引号?详情。