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

Noo*_*oob 39 linux centos script shell ubuntu

$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

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

$ echo ${name}
foo
Run Code Online (Sandbox Code Playgroud)

似乎 ${variable} 与 $variable 相同。而 $() 是执行命令。那么为什么要使用 ${} 呢?

G-M*_*ca' 59

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

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

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

${parameter}
    参数 的值被替换。当参数是一个多于一位的位置参数时,或者当参数后跟一个不被解释为其名称的一部分的字符时,需要大括号。

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

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

你也可以用引号来做到这一点:

$ echo "$animal"s
猫

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

$复数=s
$ echo $animal$plural
猫

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

如果参数的第一个字符 是感叹号 ( !),则引入了一个变量间接级别。Bash 使用由参数的其余部分形成的变量的值作为变量 的名称;这个变量然后被扩展,并且该值用于替换的其余部分,而不是参数本身的值。这称为间接扩展。?    …… (例外) ……?感叹号必须紧跟在左大括号之后才能引入间接性。

除了示例之外,我不确定如何更清楚地说明这一点:

$动物=猫
$回声$动物
猫
$猫=虎斑猫
$回声 $cat
虎斑猫
$ echo ${!animal}
tabby                            # 如果$animal“cat” ,那么${!animal}就是$cat ,即“tabby”

因此,我们将该步骤称为 1½。作为第 2 步,您可以做很多有趣的事情:

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

没有{……}大括号,你不能做任何这些事情。

位置参数

考虑这个人为的例子:

$ cat myecho.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
$ ./myecho.sh 嘿,diddle dodle,猫和小提琴,牛跳过月亮。
嘿diddlediddle,猫和小提琴,嘿0嘿1嘿2嘿3嘿4嘿5

因为外壳不理解$10,$11等。它把它$10当作${1}0。但它确实理解${10},${11}等,如手册页中所述(“多于一位的位置参数”)。

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

以上(以及更多形式的构造)在 shell 的手册页bash(1) 中进行了更详细的讨论。${parameter…something_else}

关于行情的说明

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

$ filename="童谣.txt"
$ ls -ld ${文件名}
ls:无法访问托儿所:没有这样的文件或目录
ls: 无法访问 rhyme.txt: 没有那个文件或目录
$ ls -ld "$文件名"
-rwxr-xr-x 1 Noob Noob 5309 Jul 2 11:09 童谣.txt

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

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

请参阅Bash 引号在命令替换时未转义,以 获取有关引号和$(...之间交互的简短论文)


Mar*_*iae 9

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

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

    $ 
Run Code Online (Sandbox Code Playgroud)

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


byt*_*zed 5

我通常在字符串中更常见到它。像这样的事情是行不通的:

var="a"
echo "$varRAW_STRING"
Run Code Online (Sandbox Code Playgroud)

但这会:

var="a"
echo "${var}RAW_STRING"
Run Code Online (Sandbox Code Playgroud)

正如您所说,$()用于执行命令:

dir_contents=$(ls)
Run Code Online (Sandbox Code Playgroud)

您也可以使用反引号,但我发现反$()引号更通用。一方面,反引号不能(轻易)嵌套。

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