$ VAR vs $ {VAR}并引用或不引用


Answers:


99

VAR=$VAR1是的简化版本VAR=${VAR1}。第二件事可以做,第二件事可以做,例如引用数组索引(不可移植)或删除子字符串(POSIX便携式)。请参阅POSIX规范中的《 Bash初学者指南和参数扩展》中的“ 更多关于变量的部分” 。

使用in rm -- "$VAR1"或变量周围的引号rm -- "${VAR}"是一个好主意。这使变量的内容成为原子单位。如果变量值包含空格(嗯,$IFS特殊变量中的字符,默认情况下为空格)或通配符,并且您不对其进行引用,则每个单词都被视为文件名生成(globbing),其扩展为您提供了很多参数在做。

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

关于可移植性:根据POSIX.1-2008第2.6.2节,花括号是可选的。


@shawn更新了我的问题,因为我也对可移植性感到好奇
xenoterracide 2010年

@shawn:我怀疑你的例子是正确的。您是否有外壳的实际示例,其中var1=$var扩展给出错误?
alex 2010年

@alex:谢谢。我以为我已经在命令行上进行了测试,但是我做错了。我改变了例子。
肖恩·高夫

对于更新的示例,最好记住您通常应该使用引用的版本,因为该示例是一个特例。
Alex

9
@Shawn:引号是没有必要的分配。在大多数其他用途中,它们是必需的,包括export VAR=$VAR1。至于花括号,它们是可选的(请检查您引用的本节的第四段;在所有POSIX和POSIX之前的外壳中都是这种情况)。
吉尔斯(Gilles)2010年

60

${VAR}并且$VAR是完全等价的。对于普通的变量扩展,使用的唯一原因${VAR}是在解析时否则会将太多的字符捕获到变量名中,如中所示${VAR1}_$VAR2(不带花括号将等效于${VAR1_}$VAR2)。装饰最多的扩展(${VAR:=default},,${VAR#prefix}…)需要使用花括号。

在变量赋值中,关闭了字段拆分(即,在值中的空白处拆分)和路径名扩展(即,globbing),因此在我听说过的所有POSIX shell和所有POSIX之前的sh中,它VAR=$VAR1都完全等效于VAR="$VAR1"。 。(POSIX参考:简单命令)。出于相同的原因,VAR=*可靠地设置VAR为文字字符串*;当然VAR=a b设置VAR为,a因为首先b是一个单独的词。通常,在shell语法需要一个单词的情况下,例如case … in(但不在模式中),双引号是不必要的,但是即使在那儿也需要小心:例如POSIX指定重定向目标>$filename)不需要在脚本中使用引号,但是包括bash在内的一些shell甚至需要在脚本中使用双引号。请参阅何时需要双引号?进行更彻底的分析。

在其他情况下,确实需要双引号,尤其export VAR="${VAR1}"export "VAR=${VAR1}"在许多shell中(可以等效地写成双引号)(POSIX使这种情况保持打开状态)。这种情况与简单赋值的相似性,以及不需要双引号的情况列表的分散性质,这就是为什么我建议仅使用双引号的原因,除非您确实希望拆分和使用glob。


2
通常,即使我知道该值不包含任何IFS字符,因为我想养成习惯,我也总是引用变量扩展名。一个例外是我在进行变量赋值时不引用该值(除非需要,例如,当值包含空格时)。当存在命令替换(例如)时,这使编辑器语法突出显示更加有用FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}")。而不是为所有内容都加上“字符串”颜色,而是使嵌套代码的语法高亮显示。这也是为什么我避免反引号的原因。
理查德·汉森

虽然>$file在POSIX脚本中可以,但即使非交互(除非使用$POSIXLY_CORRECT--posix... 强制执行POSIX合规性),它也不在bash中。
斯特凡Chazelas

的确确实不需要使用引号VAR=$VAR1,有时local VAR=$VAR1我有时会对感到惊讶,我记得在某些方面(至少在某些外壳中)的工作方式有所不同。但是atm,我无法重现这种分歧。
dubiousjim 2015年

好的,找到了我想起的问题。它仅在某些外壳中显示。
dubiousjim 2015年

@dubiousjim local VAR=$VAR1就像export VAR=$VAR1,它取决于shell。
吉尔斯2015年

8

报价单

考虑将双引号用于变量扩展,将单引号用于强引用(即无扩展)。

扩张:

this='foo'
that='bar'
these="$this"
those='$that'

输出:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

值得一提的是,出于多种原因,应尽可能使用引号,其中最好的一个是,它被认为是最佳实践,并且具有可读性。同样是因为Bash有时很古怪,并且经常使用看似不合逻辑或不合理/意外的方式,而引号会将隐式期望更改为显式期望,从而减少了错误表面(或潜在错误)。

尽管报价是完全合法的,并且在大多数情况下都可以使用,但该功能是为方便起见而提供的,可能不太便于携带。保证体现意图和期望的正式实践是引用。

替代

现在还要考虑该构造"${somevar}"用于替换操作。几种用例,例如替换和数组。

更换(剥离):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

更换(替换):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

数组:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

所有这些都几乎没有刮擦"${var}"替代结构的表面 。关于Bash shell脚本的权威参考是免费的在线参考TLDP The Linux Documentation Projecthttps://www.tldp.org/LDP/abs/html/parameter-substitution.html


1
非常有用。
Orion elenzil

0
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

然后结束:

env=$1
    if [ ! -f /dirname/${env}hostname ]

值得一提的是使用冰壶的更清晰示例

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.