为什么 watch bash -c '"echo $RANDOM"' 不打印任何内容?

为什么 watch bash -c '"echo $RANDOM"' 不打印任何内容?

我希望此命令每 2 秒在屏幕上打印一个随机值,但它不会打印任何内容:

watch bash -c '"echo $RANDOM"'

然而,该命令每 2 秒打印一个随机值:

watch bash -c '"echo \$RANDOM"'

显然我必须转义美元符号,但我想了解为什么,因为在第一种情况下,watch 命令在顶部报告正在正确执行命令:

Every 2.0s: bash -c "echo $RANDOM"

在第二种情况下,它报告正在执行此命令,正如预期的那样:

Every 2.0s: bash -c "echo \$RANDOM"

好吧,我明白了,必须转义美元符号才能正确到达 bash 命令。但仍然,为什么? watch 命令在执行命令之前对 $RANDOM 做了什么,使其不输出任何内容?

答案1

就像评论中提到的 @steeldriver 一样,默认情况watch下通过 运行命令sh -c。不过,它似乎首先用空格连接它得到的任何参数。

watch bash -c '"echo $RANDOM"'

它获取 args bash-c"echo $RANDOM"、 产生bash -c "echo $RANDOM",并sh使用两个 args-c和运行bash -c "echo $RANDOM"

然后是sh双引号内的变量并适当扩展它。如果您sh不支持特殊的$RANDOM,则整个变量可能未设置,并且您会得到一个空字符串。然后生成的命令是bash -c "echo ",它启动 Bash,告诉它只打印换行符。

(如果您sh是 Bash 并且确实有$RANDOM,那么您可以直接使用watch 'echo $RANDOM'。)

如果添加反斜杠,那里的外壳 ( sh) 会看到... "echo \$RANDOM",它不会扩展,只是删除反斜杠。内壳 ( bash) 看到echo $RANDOM并扩展变量本身。如果您将外壳安排为 get ... 'echo $RANDOM',则相同,并带有单引号。

您可以看到中间 shell 使用如下内容进行的扩展(它应该打印out):

export foo=out; watch 'bash -c "foo=in; echo $foo"'

使用watch -x,它会跳过介入的 shell,并且这将以您期望的方式工作,而无需引用地狱:

watch -x bash -c 'echo $RANDOM'

答案2

来自手册页

请注意,命令被赋予“sh -c”...

如果您执行echo $RANDOMusingsh而不是,bash您将不会得到任何输出,因为$RANDOM可以在 中使用bash,但不能在 中使用sh

相关内容