在 shell 脚本中,我们什么时候在扩展变量时使用 {}
?
例如,我看到了以下内容:
var=10 # Declare variable
echo "${var}" # One use of the variable
echo "$var" # Another use of the variable
有显着差异,还是只是风格?一个比另一个更受欢迎吗?
在这个特定的例子中,它没有任何区别。但是,如果您想扩展字符串中的变量 foo
,${}
中的 {}
很有用
"${foo}bar"
因为 "$foobar"
将改为扩展由 foobar
标识的变量。
在以下情况下也无条件地需要花括号:
扩展数组元素,如 ${array[42]}
使用参数扩展操作,如 ${filename%.*} (删除扩展名)
将位置参数扩展到 9 之外:“$8 $9 ${10} ${11}”
在任何地方都这样做,而不仅仅是在潜在的模棱两可的情况下,可以被认为是良好的编程习惯。这既是为了保持一致性,也是为了避免像 $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 array
echo "${dir[0]}" # get the first entry.
echo "$dir[0]" # incorrect
dir=(*)
。据我所知,dir
是列出目录内容的内置命令(相当于 ls -C -b
)。你能解释一下吗?
dir
是变量的名称,括号用于将文件名扩展 *
收集到一个数组中。
foo=(*); echo "${foo[2]}"
您还可以在大括号内进行一些文本操作:
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 变量扩展。
例如:
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
这绝对更具可读性。
由于变量名不能以数字开头,shell 不需要在编号变量(如 $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
看:
Linux 环境变量名称中允许的字符
It's good to be not over-cautious
:我想知道大多数人的想法。始终使用花括号,这样您就不会在需要时忘记它们,或者仅在需要时使用它们,以提高可读性。
变量名的结尾通常用空格或换行符表示。但是,如果我们在打印变量值后不想要空格或换行符怎么办?花括号告诉 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
(弗雷德的回答已经说明了这一点,但他的例子有点太抽象了)
根据 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 文件中的 new_word 替换单词变量内容
> sed -i "s/${word}/${new_word}/g" $sposi
> cat $sposi
输出:quel filone del lago di como che volge a mezzogiorno
“ramo”一词已被替换。
weel-known novel
位。尽管如此,还是投了赞成票。
{}
称为 brace expansion。${}
称为变量扩展。他们做不同的事情。除了没有扩展位之外,我会支持你。$()
用于执行命令,以便md5sum=$(md5sum foo.bin)
将md5sum foo.bin
的输出存储在变量md5sum
中,现在可以使用${md5sum}
访问。此外,+1 和更多精神上的 OP 提到明确表示是一种很好的做法!$()
从 subshell 执行其命令很重要。${1:-20}
是一种参数扩展形式。这里并不明显,因为它主要使用数字和算术运算符,让我们误以为涉及算术,但它实际上是指位置参数$1
,如果未定义,它将被默认值20
替换(语法是${variable:-default_value}
)。