Bash 参数扩展

作者:Mitch Frazier

如果您使用 bash,您已经知道什么是参数扩展,尽管您可能在不知其名称的情况下使用过它。任何时候您使用美元符号后跟变量名,您都在执行 bash 所谓的参数扩展,例如echo $a或者a=$b。但是参数扩展还有许多其他形式,允许您扩展参数并修改值或在扩展过程中替换其他值。

参数扩展在 bash 中有多种形式,最简单的是美元符号后跟名称,例如$a。这种形式只是将变量的值替换到参数扩展表达式的位置。变量名也可以选择用花括号括起来,例如${a}。如果变量名紧随其后的是可以作为变量名一部分的字符,则需要使用花括号来分隔变量名,例如,如果您从以下代码中删除花括号echo ${a}bcbash 将尝试扩展变量 "abc" 而不是 "a"。

参数扩展的一个有用形式是为变量设置默认值(如果变量未设置)。这可以通过以下语法完成${VAR:-DFLT}。您可以使用此功能来允许通过环境变量修改您的代码。考虑以下脚本,命名为test.sh:

  TEST_MODE=${TEST_MODE:-0}
  ...
  if [[ $TEST_MODE -eq 0 ]]; then
      echo "Running in live mode"
  else
      echo "Running in test mode"
  fi
通常脚本以 "live" 模式运行,但如果您通过以下方式运行它
  $ env TEST_MODE=1 sh test.sh
它将在测试模式下运行。

您还可以将默认值扩展与命令行参数或配置文件中的值一起使用,例如

  # set cmd_param_x to 1 if seen on the command line
  ...
  if [[ ${cmd_param_x:-0} -eq 0 ]]; then
      echo "-x not specified"
  else
      echo "-x specified"
  fi

参数扩展的另一个有用形式是扩展变量并在值上执行字符串替换,使用以下形式${VAR/search/replace}。例如

  VAR=aabbcc
  echo ${VAR/b/-dd-}
输出 "aa-dd-bcc"。请注意,只替换搜索字符串的第一个实例,如果您想替换所有实例,请使用双斜杠
  VAR=aabbcc
  echo ${VAR//b/-dd-}
现在输出 "aa-dd--dd-cc"。

还有用于删除前缀和后缀的扩展。形式${VAR#pattern}从扩展值中删除与模式匹配的任何前缀。删除的前缀是最短匹配的前缀,如果您使用双井号/哈希标记,则删除最长匹配的前缀。类似地,形式${VAR%pattern}删除匹配的后缀(单百分号表示最短后缀,双百分号表示最长后缀)。例如

  file=data.txt
  echo ${file%.*}
  echo ${file#*.}
分别输出文件基本名称和扩展名(“data” 和 “txt”)。

注意:如果您难以记住这两个语法的哪个是哪个,“#” 键在键盘上位于 “%” 键的左侧,就像前缀在后缀之前一样。另请注意,这些是 *glob* 模式,而不是正则表达式。

存在的另一个扩展是从扩展值中提取子字符串,使用以下形式${VAR:offset:length}。这以预期的形式工作:偏移量从零开始,如果您未指定长度,则会延伸到字符串的末尾。例如

  str=abcdefgh
  echo ${str:0:1}
  echo ${str:1}
输出 “a” 和 “bcdefgh”。

这种形式也接受从字符串末尾向后计数的负偏移量。所以这个

  str=abcdefgh
  echo ${str:-3:2}
产生 “abcdefgh”... 哎呀,那里发生了什么?发生的事情是 bash 误解了我们想要的内容,因为扩展看起来像默认值扩展${VAR:-DFLT}。第一次我尝试这个时,我盯着它看了很长时间,才明白如何做到这一点(不使用变量 [见下文])
  str=abcdefgh
  echo ${str:$((-3)):2}
输出所需的值 “fg”。 “$((…))” 使 bash 将该值视为算术扩展(即数字)。另一种稍长的方法是
  str=abcdefgh
  i=-3
  echo ${str:$i:2}

我要提到的参数扩展的最后一种形式是简单地扩展为变量值的长度,其形式为${#VAR}。所以例如

  str=abcdef
  echo ${#str}
输出 “6”。

在您的 shell 脚本中使用这些形式的参数扩展可以简化和缩短您的脚本。这些不是 bash 支持的唯一参数扩展形式,但它们是我随着时间推移发现最有用的形式。有关更多信息,请参阅 bash 手册页的 “Parameter Expansion” 部分。

附注:请注意,上述所有形式的参数扩展也适用于 bash 的 *特殊参数*:“$$”、“$0”、“$1” 等。

Mitch Frazier 是 Emerson Electric Co. 的嵌入式系统程序员。自 2000 年代初期以来,Mitch 一直是 Linux Journal 的撰稿人和朋友。

加载 Disqus 评论