如果标志值包含括号,则getopt $ OPTARG为空

问题描述 投票:1回答:2

当我将包含[...]的标志传递给我的bash脚本时,当我尝试使用getops获取值时,$OPTARG会给我一个空字符串。

shopt -s nullglob
while getopts ":f:" opt; do
  case $opt in
   f)
      str=$OPTARG
      ;;
  esac
done
echo ${str}

运行脚本:

$ script.sh -f [0.0.0.0]
<blank line>

如何在脚本中返回原始值?

bash echo getopts
2个回答
1
投票

简短摘要:双引号变量引用。并使用shellcheck.net

长解释:当你使用一个没有双引号的变量(例如echo ${str})时,shell会尝试将其值拆分为单词,并将看起来像通配符表达式的任何内容展开到匹配文件列表中。在[0.0.0.0]的情况下,括号使其成为通配符表达式,它将匹配字符“0”或“。”。 (相当于[0.])。如果您有一个名为“0”的文件,它将扩展为该字符串。由于没有匹配的文件,它通常保持未展开状态,但是使用nullglob设置它会扩展为... null。

如果没有匹配的文件,关闭nullglob解决了问题,但实际上并不是正确的方法。我记得(但现在找不到)一个关于在一台特定计算机上失败的脚本的问题,原因是一台计算机碰巧有一个文件与一个不带引号的变量值的括号表达式相匹配。

正确的解决方案是在变量引用周围加上双引号。这告诉shell跳过单词拆分和通配符扩展。这是一个交互式的例子:

$ str='[0.0.0.0]'    # Quotes aren't actually needed here, but they don't hurt
$ echo $str    # This works without nullglob or a matching file
[0.0.0.0]
$ shopt -s nullglob
$ echo $str    # This fails because of nullglob

$ shopt -u nullglob
$ touch 0
$ echo $str    # This fails because of a matching file
0
$ echo "$str"    # This just works, no matter whether file(s) match and/or nullglob is set
[0.0.0.0]

所以在你的脚本中,只需将最后一行更改为:

echo "${str}"

请注意,case $opt instr=$OPTARG中不需要双引号,因为这些特定上下文中的变量不受字拆分或通配符扩展的影响。但IMO跟踪哪些情况下可以安全地将双引号保留下来比使用它更加麻烦,你应该加倍引用它们。

顺便说一句,shellcheck.net善于发现像这样的常见错误;我建议通过它提供脚本,因为这可能不是你遇到这个问题的唯一地方。


1
投票

假设在更大的脚本中需要shopt -s nullglob。 你可以使用shopt -s nullglob临时禁用shopt -u nullglob

shopt -s nullglob
shopt -u nullglob
while getopts ":f:" opt; do
  case $opt in
   f)
      str=$OPTARG
      ;;
  esac
done
echo ${str}

shopt -s nullglob
© www.soinside.com 2019 - 2024. All rights reserved.