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


Answers:


39

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

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

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

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

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

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

您也可以使用引号:

$ echo“ $ animal” s
猫

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

$ plural = s
$ echo $ animal $ plural
猫

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

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

除了示例以外,我不确定如何使它更清晰:

$动物=猫
$ echo $动物
猫
$ cat =平头
$ echo $ cat
虎斑猫
$ echo $ {!animal}
tabby                            #如果 $ animal  “ cat” ,则 $ {!animal}  $ cat ,即 “ tabby”

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

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

你不能做任何的那些东西没有{...... }括号。

位置参数

考虑以下人工示例:

$猫myecho.sh
回声$ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh嘿,骗人的骗子,猫和小提琴,那头牛跳上了月亮。
嘿,骗子,猫和小提琴,嘿,嘿1,嘿2,嘿3,嘿4,嘿5

因为外壳不理解$10$11等等。它$10像对待一样${1}0。但它确实明白${10}${11}等,在手册页(“超过一个数字的位置参数”)中提到。

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

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

报价单

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

$ filename =“ nursery rhyme.txt”
$ ls -ld $ {文件名}
ls:无法访问托儿所:没有此类文件或目录
ls:无法访问rhyme.txt:没有此类文件或目录
$ ls -ld“ $文件名”
-rwxr-xr-x 1 Noob Noob 5309 7月2日11:09 Nursery rhyme.txt

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

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

有关 引号和… 之间的交互的简要论述,请参见在命令替换中未转义的Bash引号$()


感谢您的精彩示例。您能详细说明一下!在您的示例中。我不太了解它是如何工作的。
Noob 2015年

@Noob:好的,我详细介绍了的使用!
G-Man说'恢复莫妮卡'

谢谢。实际上,动物实际上是指变量cat而不是值cat。您还可以让我知道/ at在回声$ {animal / at / ow}中如何变成“ c”吗?bash的男人解释是某种方式……我不知道。很难明白。
Noob 2015年

另外,您能否详细说明一下这句话-“ $ {parameter}替换为参数的值。” 用什么代替?如果参数为fruit并且其值为apple-fruit = apple,则$ {fruit}-apple被替换为??。并没有真正取代这里的含义
Noob 2015年

@Noob:“ ${!animal}实际上是在指变量$cat而不是值cat。”是的,这就是重点。“ / at在回声$ {animal / at / ow}中如何变成“ c”?”嗯?/ at不会变成“ c”;当“ at”替换为“ ow”时,“ cat”变为“ cow”。
G-Man说'恢复莫妮卡'

7

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

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

    $ 

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


4

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

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

实际上,反引号可以嵌套:date_directory=`ls \`date '+%Y-%m-%d'\``。但这是丑陋的。$(…)更清晰易用。
G-Man说'恢复莫妮卡'

好,可以。从技术上讲这是可能的,但我无法想象有人会因为可读性而
这么做

1
好吧,`…`是数年前发明(唯一的)用于命令替换的语法$(…),因此您无需想像任何东西,人们已经做到了。
G-Man说'

s /曾经做过/已经做过/
字节大小的
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.