什么时候需要在外壳变量周围花括号?


657

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

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

var=10        # Declare variable

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

是否存在重大差异,还是仅仅是样式?是一个比另一个更好的选择吗?

Answers:


749

在此特定示例中,没有区别。但是,如果要扩展字符串中的变量,则{}in ${}很有用foo

"${foo}bar"

因为"$foobar"它将改为扩展由标识的变量foobar

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

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

这样无处不在,而不是只在潜在不确定的情况下,可以被认为是良好的编程习惯。这既是为了保持一致性,又是为了避免类似的意外情况$foo_$bar.jpg,在下划线看起来不是变量名的一部分在视觉上并不明显。


106
{}被称为支撑扩展${}被称为变量扩展。他们做不同的事情。除了没有扩展性,我会投票给你。
Spencer Rathbun 2012年

5
@NewUser“ 因此,除了数组之外,它并不是真正需要的 ”不是,括号对于PARAMETER EXPANSION是必需的,这是脚本编写中非常有用的结构。我看过许多sed和awk脚本,可以用一些参数扩展代替它们。
SiegeX 2012年

10
@caffinatedmonkey $()用于执行命令,这样md5sum=$(md5sum foo.bin)会将命令的输出存储md5sum foo.bin在变量中md5sum,现在可以使用进行访问${md5sum}。此外,OP还要在+1上更加精神,因为要明确指出这是一个好习惯!
L0j1k 2015年

11
@ L0j1k说到显式性,我发现提到$()subshel​​l执行其命令很重要。
AdrianGünter'15

2
@karatedog ${1:-20}是参数扩展的一种形式。在此并不明显,因为它主要使用数字和算术运算符,使我们误以为涉及算术,但实际上是指位置参数$1,如果未定义,它将被默认值替换20(语法为${variable:-default_value})。
亚伦

126

在没有$和没有的情况下声明和分配变量{}。你必须用

var=10

分派。为了从变量中读取(换句话说,“扩展”变量),必须使用$

$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它并没有实现您可能认为的那样!


34

{}用于分组。需要大括号来取消引用数组元素。例:

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

第一行我听不懂dir=(*)。据我所知,这dir是一个内置命令来列出目录内容(等效于ls -C -b)。你能解释一下吗?
贾维斯(Jarvis)

1
在Shell编程中,命令和参数必须用空格分隔。在这里,您会看到没有空格的等号,这意味着这是一个变量赋值。 dir是变量的名称,括号用于将文件名扩展收集*到数组中。
格伦·杰克曼

27

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

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

结果:

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

要么

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

结果:

This_is_a_string

您是正确的,不需要“常规变量” ...但是它对于调试和阅读脚本更有用。


11

变量名的末尾通常用空格或换行符表示。但是,如果我们在打印变量值后不想要空格或换行符怎么办?花括号告诉shell解释器变量名的末尾在哪里。

经典示例1)-没有尾随空格的shell变量

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类路径

# 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

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


5

访问数组元素和执行括号扩展始终需要弯括号。

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

例如:

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

因此,最好将三行写为:

path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

绝对更易读。

由于变量名不能以数字开头,因此外壳程序不需要{}在编号的变量周围(例如$1$2等),除非在此类扩展名后加上数字。这太微妙了,确实可以{}在以下上下文中明确使用:

set app      # set $1 to app
fruit=$1le   # sets fruit to apple, but confusing
fruit=${1}le # sets fruit to apple, makes the intention clear

看到:


1
It's good to be not over-cautious我不知道大多数人的想法。始终使用花括号,这样您就不会在需要时忘记它们,或者仅在需要时使用它们,以提高可读性。
Roger Dahl

1
我认为正是由于缺乏认识,导致程序员即使在不需要时也使用curly。这种无知类似于另一个常见的错误,即不使用双引号来防止无意中出现单词分裂或乱码现象。从根本上说,现实是程序员对Shell脚本的重视程度不如Python和Ruby等其他脚本语言那么严重。
codeforester

1
诚然。我的烦恼是,每个人似乎都认为shell脚本中的所有变量都应该全部大写:)
Roger Dahl

2

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

假设您有一个sposi.txt文件,其中包含一部意大利著名小说的第一行:

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

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

现在创建两个变量:

# 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文件中的word变量内容替换为new_word之一

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

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

“ ramo”一词已被替换。


1
在变量周围没有花括号的情况下,效果也是如此。
阿玛利

您可能需要修复该weel-known novel位。尽管如此,仍然支持。
gsl
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.