echo“ date”,echo“ date”和echo“ date”有什么区别?


23

这三个命令有什么区别?

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

我对实际的差异感到困惑。我认为,当'周围时,表示它是一个字符串,因此echo将按字面意义输出该字符串date而不是显示日期?

Answers:


19

“日期”将仅扩展到date命令的输出。但是,它将在输出中有多个连续的空格字符的地方删除多余的空格字符。(这是因为命令替换会受到单词拆分的影响,并且因为echo命令如何处理多个参数。)

“`date`”中,双引号是弱引号,因此它们将扩展变量(尝试“ $ PWD”)并执行命令替换。扩展结果作为单个参数传递给echo命令,其中包括任何连续的空格:即,执行单词拆分。

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

请参阅此链接以获取更多说明。

编辑了迈克尔·塞尔曼(Michael Suelmann)在以下评论中正确指出的第一点。


1
围绕日期的`字符到底叫什么?如果我理解正确,元字符将不能用单引号引起来?
约翰·

如果我理解正确,元字符将不能用单引号引起来?
约翰

8
在那种情况下和各种Unix文档/书籍中,`通常被称为“反引号”。像这样单独使用时,它实际上并没有用作Unicode的重音符号,即使那是符号的名称。而且您是正确的,如果用单引号引起来,则不会扩展元字符/表达式。
2013年

您的第一条陈述不正确,因为根据日期或区域设置,输出可能会略有不同。仅第二条命令将输出与裸date命令相同的内容。
jlliagre

1
@BonsiScott HTML中也删除了“ Nov”和“ 1”之间的多余空间;)
Izkata

16

echo `date`

echo "`date`"

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

但是有一个区别:用"引号"引起来的引号将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`" joeuser@example.com

但这会通过发送7个参数来混淆脚本:

foo `date` joeuser@example.com

3
您的第一句话很自相矛盾。第一种形式和第二种形式不一定会输出与您稍后演示的相同的东西。
jlliagre 2013年

谢谢。我更改了措辞以使其更清楚。
吉姆·斯图尔特

3

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

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

但是,如果不在双引号中和列表上下文中(例如,在像echo您这样的简单命令的参数中),则该扩展还受以下条件的限制:

  1. 单词拆分:即根据变量的当前值(默认情况下包含空格,制表符和换行符(以及NUL带有))将“拆分后的换行符的输出date拆分成几个单词$IFSzsh

    例如,如果date输出Fri 1 Nov 14:11:15 GMT 2013\n(如经常在英语语言环境,并在内地英国时区所做的),和$IFS目前包含:,将被分成3个Fri 1 Nov 141115 GMT 2013

  2. 文件名生成(又名通配符)(除外zsh):是,从上面的分裂所产生的每个字找通配符(*?[...]虽然有些炮弹有更多的),并扩大到匹配模式,文件名列表。例如,如果输出date?%? 33 */*/* UVC 3432(像它往往是在金星的语言环境和UVC时区),并且$IFS是默认值),那么膨胀到所有非隐藏的3个字符的文件名在当前目录中中间性格%33,当前目录的所有非隐藏子目录的所有非隐藏子目录中的所有非隐藏文件,UVC以及3432

这就是为什么:

  1. 除非您确实希望拆分单词生成文件名,否则应始终用引号(双引号)引起来扩展时来
  2. 如果您确实想要分,则应设置$IFS其为要拆分的字符。
  3. 如果确实要拆分单词而不是生成文件名,则需要发出a set +f来禁用它。

单引号引用所有内容,因此会使反引号字符按字面意义使用。

示例(使用-x可以更轻松地查看正在发生的事情):

$ bash --norc -x
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字符,则外壳的行为各不相同:有的将其删除,有的在第一个NUL字符处截断了输出,zsh保留了它们,但请注意,无论如何外部命令都不能接受包含NUL的参数


没有实际的“ POSIX shell”之类的东西。通过使用外壳程序的功能的有限子集,它们可以符合各种相关的POSIX标准。
fpmurphy '17

0

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

使用“`date`”,由于双引号之间有命令替换,因此您将date的输出作为一个单词/参数获得,但是该输出未进一步解析。在下面的示例中,变量扩展如“ $ i”同样有效。

使用“`日期”,您会得到一个字面的“日期”,因为单引号之间没有命令替换。

也许这三种形式的差异将以这种方式更加明显:

> 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`
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.