shell 脚本中 ${} 和 $() 之间的区别

shell 脚本中 ${} 和 $() 之间的区别
$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

$ name=foo
$ echo $(name)
ksh: name:  not found

$ echo ${name}
foo

好像${variable}和 一样$variable,而$()是执行命令。为什么要用${}then?

答案1

$(command)是“命令替换”。正如你所理解的,它运行command,捕获其输出,并将其插入到包含$(…);例如,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}是“参数替换”。在 shell 的 man 页面中可以找到很多信息,重击(1), 在下面 ”参数扩展”标题:

${parameter}
    的价值范围被替换。以下情况需要使用括号范围是具有多于一位数字的位置参数,或者当范围后面跟着一个不应被解释为其名称一部分的字符。

有关位置参数,请参阅“位置参数”,如下。在最常见的用法中,如其他答案所示, parameter是变量名。${…}如上段末尾所述,该形式允许您获取变量的值(即),并在其后紧跟字母、数字或下划线:$variable_name

$ 动物=猫
$ 回显 $animals
                                # 没有这样的变量“动物”。
$ echo ${animal}s
$ 回显 $animal_food
                                # 没有这样的变量“动物食物”。
$ 回显 ${animal}_food
猫食

您也可以使用引号来执行此操作:

$ echo "$animal"s

或者,作为选项练习,您可以使用第二个变量:

$ 复数=s
$ echo $animal$plural

但这只是第一步。手册页中的下一段很有趣,尽管有点神秘:

如果第一个字符范围 是一个感叹号(!),引入了一层变量间接寻址。Bash 使用由其余变量组成的变量的值范围 作为变量的名称;然后扩展此变量,并在其余的替换中使用该值,而不是范围本身。这被称为间接扩张。     (例外)...   感叹号必须紧跟在左括号后面,以引入间接引用。

除了举例之外,我不知道如何才能更清楚地说明这一点:

$ 动物=猫
$ echo $animal
$ cat=tabby
$ 回显 $cat
虎斑猫
$ 回显 ${!animal}
虎斑猫                           # 如果$动物“猫”, 然后${!动物}$猫, IE,“虎斑猫”

所以我们将其称为步骤 1½。步骤 2 中您可以做很多有趣的事情:

$ 动物=猫
$ echo ${#animal}
3                               # 字符串长度
$ echo ${animal/at/ow}
奶牛                             # 代换

{如果没有牙套,你就无法做任何事}

位置参数

考虑一下人造的例子:

$ cat myecho.sh
回显 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
$ ./myecho.sh 嘿,diddle diddle,猫和小提琴,牛跳过了月亮。
嘿,骗子骗子,猫和小提琴,Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

因为 shell 无法理解$10$11等。它将$10其视为${1}0。但它确实理解${10}${11}等,正如手册页中提到的那样(“具有多位数字的位置参数”)。

但实际上不要这样编写脚本;有更好的方法来处理长参数列表。

上述内容(以及更多形式的构造)在 shell 的手册页中有更详细的讨论,${parameter…something_else}重击(1)

关于引文的说明

请注意,除非有充分理由不这样做,否则你应该始终引用 shell 变量,并且你当然你知道自己在做什么。相比之下,虽然括号很重要,但它们并不像引号那么重要。

$ filename="童谣.txt"
$ ls -ld ${文件名}
ls:无法访问 Nursery:没有此文件或目录
ls:无法访问 rhyme.txt:没有此文件或目录
$ ls -ld "$文件名"
-rwxr-xr-x 1 Noob Noob 5309 7月 2 11:09 童谣.txt

这也适用于位置参数(即命令行参数;例如"$1")以及命令替换:

$ ls -ld $(date "+%B %Y").txt
ls:无法访问 July:没有此文件或目录
ls:无法访问 2015.txt:没有此文件或目录
$ ls -ld "$(日期 "+%B %Y").txt"
-rwxr-xr-x 1 Noob Noob 687 2015 年 7 月 2 日 11:09.txt

Bash 命令替换时不转义引号$(了解有关引文与…… 之间相互作用的简要论述)

答案2

在您的示例中,$var 和 ${var} 相同。但是,当您希望在字符串中扩展变量时,花括号很有用:

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

因此,花括号提供了一种替换变量的方法,以便获得要替换的新变量的名称。

答案3

我通常在字符串中更常见到这种情况。类似下面的代码不会起作用:

var="a"
echo "$varRAW_STRING"

但这将:

var="a"
echo "${var}RAW_STRING"

正如您正确指出的那样,$()用于执行命令:

dir_contents=$(ls)

你也可以使用反引号,但我发现它$()更通用。首先,反引号不能(轻易)嵌套。

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better

相关内容