什么时候我们需要在shell变量周围使用花括号?

在shell脚本中,我们在扩展变量时什么时候使用{}

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

var=10        # Declare variable
echo "${var}" # One use of the variableecho "$var"   # Another use of the variable

有明显的区别吗,还是只是款式?一个比另一个更受欢迎?

337291 次浏览

在这个特殊的例子中,它没有区别。但是,如果您想在字符串中展开变量foo${}中的{}很有用

"${foo}bar"

因为"$foobar"会扩展foobar标识的变量。

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

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

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

变量的声明和赋值没有${}。您必须使用

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并没有做你可能认为它做的事情!

您使用{}进行分组。需要大括号来取消引用数组元素。示例:

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

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

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

结果:

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

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

结果:

This_is_a_string

你是对的,“常规变量”是不需要的……但它对调试和阅读脚本更有帮助。

变量名的结尾通常用空格或换行符表示。但是,如果我们在打印变量值后不需要空格或换行符怎么办?花括号告诉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)Java具有版本化jar的类路径

# WRONG - no such variable LATESTVERSION_srcCLASSPATH=hibernate-$LATESTVERSION_src.zip:hibernate_$LATEST_VERSION.jar
# RIGHTCLASSPATH=hibernate-${LATESTVERSION}_src.zip:hibernate_$LATEST_VERSION.jar

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

根据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"

现在将变量内容替换为new_word变量内容,在sposi.txt文件中

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

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

“拉莫”一词已被替换。

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

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

例如:

dir=logprog=foopath=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable namelogfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable namepath_copy=${path}             # {} is totally unnecessaryarchive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

所以,最好把这三行写成:

path=/var/$dir/$proglogfile=$path/$prog.logpath_copy=$path

这肯定更具可读性。

由于变量名不能以数字开头,因此shell不需要在编号变量(如$1$2等)周围使用{},除非此类扩展后跟数字。这太微妙了,确实会在这样的上下文中显式使用{}

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

见: