我可以写

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"


我的最终结果似乎都差不多。我为什么要写一个或另一个?这些不是便携式/ POSIX吗?

#1 楼

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

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-12-16 13:46

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

– alex
2010-12-16 14:48

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

– Shawn J. Goff
2010-12-16 15:19



对于更新后的示例,最好记住您通常应该使用引用的版本,因为该示例相当简单。

– alex
2010-12-16在16:15

@Shawn:作业中不需要引号。它们在大多数其他用途中都是必需的,包括导出VAR = $ VAR1。至于花括号,它们是可选的(请检查所引用部分的第四段;在所有POSIX和POSIX之前的外壳中都是这种情况)。

–吉尔斯'所以-不再是邪恶的'
2010-12-16 19:13

#2 楼

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

在变量赋值中,字段拆分(即,在值的空白处拆分)和路径名扩展(即,globbing)已关闭,因此VAR=$VAR1在我听说过的所有POSIX shell和所有POSIX之前的sh中,它完全等同于VAR="$VAR1"。 (POSIX参考:简单命令)。由于相同的原因,VAR=*可靠地将VAR设置为文字字符串*;当然,由于VAR=a b首先是一个单独的单词,因此VAR会将a设置为b。一般而言,在shell语法需要一个单词的情况下,例如在case … in中(但不在模式中),双引号是不必要的,但是即使在那儿也需要小心:例如POSIX指定重定向目标(>$filename)不需要在脚本中加引号,但是即使在脚本中,包括bash在内的一些shell都需要双引号。请参阅何时需要双引号?为了进行更彻底的分析。在其他情况下,尤其是在许多shell中,特别是在export VAR="${VAR1}"(可以等效地写为export "VAR=${VAR1}")中,确实需要双引号(POSIX使此例保持打开状态)。这种情况与简单赋值的相似性,以及不需要双引号的情况列表的分散性质,这就是为什么我建议仅使用双引号的原因,除非您确实希望拆分和使用glob。

评论


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

–理查德·汉森(Richard Hansen)
2013年1月4日19:19



虽然在POSIX脚本中> $ file是可以的,但即使是非交互式的,它也不是bash(除非使用$ POSIXLY_CORRECT或--posix ...强制执行POSIX遵从性)。

–StéphaneChazelas
13年1月23日在15:01

虽然确实在VAR = $ VAR1中不需要引号,但有时我对本地VAR = $ VAR1感到惊讶,我记得在某些方面,至少在某些外壳中,它们的工作方式有所不同。但是atm,我无法重现这种分歧。

– dubiousjim
2015年9月19日上午8:31

好的,找到了我记得的问题。它仅在某些外壳中显示。

– dubiousjim
2015年9月19日上午10:47

@dubiousjim本地VAR = $ VAR1类似于export VAR = $ VAR1,它取决于外壳程序。

–吉尔斯'所以-不再是邪恶的'
2015年9月19日下午13:17

#3 楼

引用

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

扩展:

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 Linux文档项目https://www.tldp.org/LDP/abs/html/parameter-substitution.html

评论


非常有用。

– Orion elenzil
19 Mar 20 '19在17:04

当您只知道大约1%的家庭黑客对bash变量引用有所了解时。

– RichieHH
20 Dec 26'5:37

#4 楼

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=
    if [ ! -f /dirname/${env}hostname ]


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