在 shell 脚本中,如果我定义一个变量,例如,将其引用为和 之间FOO=25
是否有区别?$FOO$
${FOO}$
答案1
在大多数情况下和$var
是${var}
相同的。(请注意,不能$
在末尾使用a!)
需要使用花括号的一个例子是当您需要将变量放入连续字符串中时。
例子:
var=hel
echo ${var}lo
将输出hello
。
答案2
要回答你的主要问题,${foo}
叫做“参数扩展”。准确地说, 本身$
开始参数扩展,{ }
实际上是可选的,根据POSIX 规范,但可以用于指示变量名称的结束:
$ foo="bar"
$ echo $fooBaz ## fails, no variable named $fooBaz exists
$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz
基本上,$foo
和${foo}
是相同的。除了上述情况或您正在执行的操作字符串操作,它们完全等价。
但是,你实际上不应该使用它们中的任何一个。经验法则是,除了极少数例外,你应该总是使用"$foo"
或,"${foo}"
而不要使用$foo
或${foo}
。您应该始终引用变量以避免调用 split+glob 运算符(稍后会详细介绍)。您当然不希望这样$foo$
。最后的$
是无关紧要的:
$ foo="bar"
$ echo "$foo$"
bar$
因此,虽然不加引号的变量有时是可以的:
$ echo $foo
bar
它们通常不是并且应该真正避免:
$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty
$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty
请注意,括号在这里也无用:
$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi ## fails
empty
$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty
当您使用$foo
或时${foo}
,shell 将分裂将变量中保存的空格值(可以通过将变量设置IFS
为其他值来更改)放入列表中,然后列表中的每个元素都被视为全局模式并扩展到任何匹配的文件或目录中。这被称为分裂+统一运算符。为了说明这一点,请考虑一个包含两个文件的目录:
$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct 9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct 9 18:16 file2
现在,让我们设置一个变量foo *
:
$ foo="foo *"
如果我们尝试检查是否存在该名称的文件,会发生什么?
$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists
变量被拆分为foo
和*
,由于是*
匹配任何字符串的通配符,因此 shell 会告诉您有一个名为foo *
exxists 的文件。但是,如果我们正确引用它,则不会发生这种情况:
$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file
这是一个用来说明这一点的简单例子。想象一下如果我用thoughrm
代替echo
。
因此,第一条规则是:总是引用你的变量。您可以使用"$foo"
或"${foo}"
但可以以任意方式引用它。有关安全使用变量的更多详细信息,请查看以下帖子: