Bash 什么时候外壳变量周围需要大括号?

Bash 什么时候外壳变量周围需要大括号?,bash,shell,syntax,curly-braces,Bash,Shell,Syntax,Curly Braces,在shell脚本中,何时在扩展变量时使用{} 例如,我看到了以下内容: var=10 # Declare variable echo "${var}" # One use of the variable echo "$var" # Another use of the variable 是有显著的区别,还是仅仅是风格?一个比另一个好吗?在这个特定的例子中,它没有区别。但是,如果要展开字符串中的变量foo,则${}中的{}非常有用 "${foo}bar" 由于“$fooba

在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

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

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

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

结果:

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

你是对的,在“正则变量”是不需要的。。。但它对调试和读取脚本更有帮助。

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

经典示例1)-不带尾随空格的shell变量 示例2)带有版本化JAR的Java类路径
(Fred的回答已经说明了这一点,但他的示例有点过于抽象)

根据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文件中的新单词替换单词variable content

> sed -i "s/${word}/${new_word}/g" $sposi
> cat $sposi
输出:
quel filone del lago di como che volge a mezzogiorno


“ramo”一词已被替换

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

最好不要过于谨慎,使用
{}
进行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

见:


    • {}
      被称为<代码>${}称为变量扩展。他们做不同的事情。除了无扩展位之外,我将向上投票。@NewUser“除了数组之外,它不是真正需要的”不是这样,大括号是脚本中非常有用的构造所必需的。我见过许多sed和awk脚本可以用一些参数扩展来代替。@caffinatedmonkey
      $()
      用于执行命令,这样
      md5sum=$(md5sum foo.bin)
      md5sum foo.bin
      的输出存储在变量
      md5sum
      中,现在可以使用
      ${md5sum}
      访问该变量。此外,+1和更多的精神,以OP提到它的良好做法是明确的@L0j1k说到明确性,我发现重要的一点是,
      $()
      从一个@karatedog
      ${1:-20}
      是参数扩展的一种形式。这里不明显,因为它主要使用数字和算术运算符,这让我们误以为涉及算术,但它实际上指的是位置参数
      $1
      ,如果没有定义,它将被默认值
      20
      (语法是
      ${variable:-default\u value}
      )。在变量周围没有大括号的情况下,这同样有效。您可能需要修复
      这一已知的新的
      位。尽管如此,我还是无法理解第一行
      dir=(*)
      。据我所知,
      dir
      是一个用于列出目录内容的内置命令(相当于
      ls-C-b
      )。您能解释一下吗?在shell编程中,命令和参数必须用空格隔开。在这里,您可以看到没有空格的等号,这意味着这是一个变量赋值
      dir
      是变量的名称,括号用于将文件名扩展名
      *
      收集到一个数组中。@Jarvis在本例中,dir这个词除了作为接受赋值的变量外没有其他意义。通过使用foo作为变量可以看到这一点<代码>foo=(*);echo“${foo[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