引述

引述

我可以写

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

对我来说,最终结果似乎都差不多。为什么我应该写其中之一?其中有哪些不是可移植/POSIX 的吗?

答案1

VAR=$VAR1是 的简化版本VAR=${VAR1}。有些事情第二个可以做,而第一个不能,例如引用数组索引(不可移植)或删除子字符串(POSIX-可移植)。请参阅有关变量的更多信息Bash 初学者指南的部分参数扩展在 POSIX 规范中。

在变量周围使用引号(如rm -- "$VAR1"or中的引号)rm -- "${VAR}"是一个好主意。这使得变量的内容成为原子单元。如果变量值包含空格($IFS特殊变量中的字符,默认情况下为空格)或通配字符并且您不引用它,则每个单词都会被考虑用于文件名生成(通配),其扩展会为您提供尽可能多的参数正在做。

$ 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 节,花括号是可选的。

答案2

${VAR}$VAR完全等价。对于普通变量扩展,使用的唯一原因${VAR}是解析会在变量名称中获取太多字符,如${VAR1}_$VAR2(不带大括号相当于${VAR1_}$VAR2)。大多数装饰性扩展(${VAR:=default}${VAR#prefix}、 ...)都需要大括号。

在 csh、tcsh 或 zsh(ksharrays未启用该选项时)中,$var[1]${var[1]}$var:modifier相同,因此如果您想要扩展后跟文字或: ,${var:modifier}您还需要大括号。$var[1]:modifier${var}[1] ${var}:modifier

在标量(与数组或关联数组相反)变量赋值中,场分裂(即在值中的空格处分割)和路径名扩展(即 globbing)被关闭,因此在我听说过的所有 POSIX shell 和所有 POSIX 之前的 sh 中VAR=$VAR1完全等同于, 。 VAR="$VAR1"(POSIX 参考:简单的命令)。出于同样的原因,VAR=*可靠地设置VAR为文字字符串*;当然VAR=a b设置VAR为,a因为 theb首先是一个单独的词。一般来说,当 shell 语法需要单个单词时,双引号是不必要的,例如case … in(但不是在模式中),但即使在那里你也需要小心:例如 POSIX 指定重定向目标( >$filename) 不需要在脚本中加引号,但一些 shell(包括 bash)甚至在脚本中也需要双引号。看什么时候需要双引号?以进行更彻底的分析。

在其他情况下,您确实需要双引号,特别是在许多 shell 中export VAR="${VAR1}"(可以等效地写成export "VAR=${VAR1}")(POSIX 保留这种情况)。这种情况与简单赋值的相似性,以及不需要双引号的情况列表的分散性,就是为什么我建议只使用双引号,除非您确实想要拆分和通配符。

答案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 脚本的权威参考是 libre 在线参考,TLDP Linux 文档项目https://www.tldp.org/LDP/abs/html/parameter-substitution.html

相关内容