关于bash:我们什么时候需要围绕shell变量的花括号?

When do we need curly braces around shell variables?

在shell脚本中,扩展变量时何时使用{}

例如,我看到了以下内容:

1
2
3
4
var=10        # Declare variable

echo"${var}" # One use of the variable
echo"$var"   # Another use of the variable

是有显著的区别,还是只是风格?一个比另一个更受欢迎吗?


在这个特定的例子中,它没有任何区别。但是,如果要扩展字符串中的变量foo${}中的{}非常有用。

1
"${foo}bar"

由于"$foobar"将改为扩大foobar

在下列情况下,也无条件地需要大括号:

  • 扩展数组元素,如${array[42]}
  • 使用参数扩展操作,如${filename%.*}(删除扩展)
  • 将位置参数扩展到9以外:"$8 $9 ${10} ${11}"

在任何地方都这样做,而不仅仅是在可能不明确的情况下,可以被视为良好的编程实践。这既是为了一致性,也是为了避免像$foo_$bar.jpg这样的意外,因为在视觉上,下划线不是变量名的一部分。


变量的声明和赋值不带${}。你必须使用

1
var=10

指派。为了读取变量(换句话说,"展开"变量),必须使用$

1
2
3
4
$var      # use the variable
${var}    # same as above
${var}bar # expand var, and append"bar" too
$varbar   # same as ${varbar}, i.e expand a variable called varbar, if it exists.

这有时让我感到困惑——在其他语言中,我们以同样的方式引用变量,不管它是在赋值的左边还是右边。但是shell脚本是不同的,$var=10并没有像您想象的那样做!


使用{}进行分组。取消对数组元素的引用需要大括号。例子:

1
2
3
dir=(*)           # store the contents of the directory into an array
echo"${dir[0]}"  # get the first entry.
echo"$dir[0]"    # incorrect


您还可以在大括号内执行一些文本操作:

1
2
STRING="./folder/subfolder/file.txt"
echo ${STRING} ${STRING%/*/*}

结果:

1
./folder/subfolder/file.txt ./folder

1
2
STRING="This is a string"
echo ${STRING// /_}

结果:

1
This_is_a_string

你在"规则变量"中是对的,不需要…但它对调试和读取脚本更有用。


变量名的结尾通常用空格或换行符表示。但如果在打印变量值后不需要空格或换行符呢?大括号告诉shell解释器变量名的结尾在哪里。

经典示例1)-不带尾随空格的shell变量

1
2
3
4
5
6
7
TIME=10

# WRONG: no such variable called 'TIMEsecs'
echo"Time taken = $TIMEsecs"

# What we want is $TIME followed by"secs" with no whitespace between the two.
echo"Time taken = ${TIME}secs"

示例2)具有版本化JAR的Java类路径

1
2
3
4
5
# WRONG - no such variable LATESTVERSION_src
CLASSPATH=hibernate-$LATESTVERSION_src.zip:hibernate_$LATEST_VERSION.jar

# RIGHT
CLASSPATH=hibernate-${LATESTVERSION}_src.zip:hibernate_$LATEST_VERSION.jar

(弗雷德的回答已经说明了这一点,但他的例子有点抽象)


访问数组元素和执行大括号扩展时总是需要大括号。

最好不要过于谨慎,即使没有歧义的余地,也可以使用{}来扩展shell变量。

例如:

1
2
3
4
5
6
dir=log
prog=foo
path=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable name
logfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable name
path_copy=${path}             # {} is totally unnecessary
archive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

因此,最好将这三行写成:

1
2
3
path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

这绝对是更可读的。

见:

  • Linux环境变量名中允许的字符


根据Sierrax和Peter关于文本操作的建议,使用大括号{}将变量传递给命令,例如:

假设您有一个sposi.txt文件,其中包含一本意大利Weel已知小说的第一行:

1
2
> sposi="somewhere/myfolder/sposi.txt"
> cat $sposi

输出:quel ramo del lago di como che volge a mezzogiorno

现在创建两个变量:

1
2
3
4
5
# Search the 2nd word found in the file that"sposi" variable points to
> word=$(cat $sposi | cut -d"" -f 2)

# This variable will replace the word
> new_word="filone"

现在用sposi.txt文件中的一个新单词替换单词变量内容。

1
2
> sed -i"s/${word}/${new_word}/g" $sposi
> cat $sposi

输出:quel filone del lago di como che volge a mezzogiorno

单词"ramo"已被替换。