echo `date`、echo "`date`" 和 echo '`date`' 之间有什么区别?

echo `date`、echo "`date`" 和 echo '`date`' 之间有什么区别?

这三个命令有什么区别呢?

echo `date`
echo "`date`"
echo '`date`'

我对实际上的差异是什么感到困惑。我认为当 ' 周围时意味着它是一个字符串,因此 echo 会字面地输出字符串date而不是显示日期?

答案1

`日期`只会扩展到date命令的输出。但是,它会在输出中有多个连续空格字符的地方删除多余的空格字符。(这是因为命令替换会进行分词,并且因为命令echo处理多个参数的方式。)

“`日期`”,双引号是弱引号,因此它们将扩展变量(尝试“$PWD”)并执行命令替换。扩展的结果作为单身的命令的参数echo,包含任何连续的空格:也就是说,分词是不是执行。

''日期``,单引号是更强的引号,因此它们不允许在其中扩展变量或命令替换。

参考这个链接了解更多解释。

编辑了 Michael Suelmann 在 中正确指出的第一点下面评论

答案2

两个都

echo `date`

echo "`date`"

将显示日期。后者的输出看起来像是date单独运行的输出。

不过,还是有区别的:用"引号括起来的参数将作为单个参数"发送到 to 。echo引号将整个命令的输出封装为一个参数。由于echo只是按顺序打印出其参数,中间有空格,所以它看起来基本上是一样的。

这是一个细微差别的例子:

echo `date`

产生:

Fri Nov 1 01:48:45 EST 2013

但:

echo "`date`"

产生:

Fri Nov  1 01:48:49 EST 2013

请注意,后面的两个空格Nov已减少为一个(不带引号)。这是因为 shell 正在解析每个空格分隔的元素并将结果作为 6 个参数发送到 echo。当您引用它时,echo 接收一个参数,并且引号保留空格。

这在除 echo 之外的命令中变得更加重要。例如,假设一个命令foo需要两个参数:日期和电子邮件地址。

这将在这种情况下起作用:

foo "`date`" [email protected]

但这会向脚本发送 7 个参数,从而使脚本感到困惑:

foo `date` [email protected]

答案3

在 POSIX shell 中,`date`是命令替换的古老形式。现代语法是$(date).

在这两种情况下,它们都会扩展为 的输出,date并删除尾随换行符(前提是输出不包含 NUL 字符)。

但是,当不在双引号内和列表上下文中时(例如在简单命令的参数中,如echo您的情况),该扩展进一步受以下约束:

  1. 分词: 那就是“输出date删除了尾随换行符”根据$IFS变量的当前值(默认包含空格、制表符和换行符(以及 NUL 和zsh))拆分为几个

    例如,如果date输出Fri 1 Nov 14:11:15 GMT 2013\n(就像在英语语言环境和英国大陆时区中经常做的那样),并且$IFS当前包含:,那么它将被分成 3 个Fri 1 Nov 141115 GMT 2013

  2. 文件名生成(又名通配)(除了zsh):也就是说,上面分割产生的每个单词都会查找通配符(*, ?[...]尽管某些 shell 有更多),并扩展到与这些模式匹配的文件名列表。例如,如果 的输出date?%? 33 */*/* UVC 3432(就像在金星语言环境和 UVC 时区中经常出现的那样),并且$IFS是默认值),那么它将扩展到当前目录中中间字符为%, 33,的所有非隐藏 3 字符文件名。当前目录所有非隐藏子目录的所有非隐藏子目录中的所有非隐藏文件,UVC以及3432.

因此:

  1. 您应该始终引用(用双引号)命令替换,除非您确实想要分词或者文件名生成在其扩展时执行
  2. 如果你确实想要分词,那么你应该设置$IFS为你想要分割的字符。
  3. 除了 zsh 之外,如果你愿意的话分词不是 文件名生成,您需要发出set -o noglob(又名set -f)来禁用它。

单引号引用所有内容,因此会导致反引号字符按字面意思理解。

示例(使用-o xtrace可以更容易地了解发生了什么):

$ bash --norc -o xtrace
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

如果输出包含 NUL 字符,则不同 shell 的行为会有所不同:有些会删除它们,有些会在第一个 NUL 字符处截断输出,zsh保留它们,但请注意,无论如何外部命令都不能接受包含 NUL 的参数

答案4

使用“date”,您可以将日期的输出拆分为多个单词,因为单词拆分是在命令替换后完成的。

使用“`date`”,您可以将日期输出作为一个单词/参数,因为双引号之间存在命令替换,但输出不会进一步解析。对于像下面的示例中的“$i”这样的变量扩展也是有效的。

使用“date”,您会得到一个文字“date”,因为单引号之间没有命令替换。

也许这样 3 种形式的差异会更加明显:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`

相关内容