在对字符串中的特殊字符采取措施后,会导致BASH错误“[:参数太多”?

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

我正在编写一个简单的脚本来检查一些存储库更新,如果需要,我正在从这些更新中创建新的软件包以安装它所引用的那些程序的新版本(在Arch Linux中)。所以我在执行真实脚本之前做了一些测试。

问题是我从这段代码中得到错误[: excessive number of arguments(但我认为正确的翻译将是[: too many arguments):

# Won't work despite the double quoted $r
if [ "$r" == *"irt"* ]; then
    echo "TEST"
fi

代码是通过添加双方括号来修复的,我感谢@this SO answer制作的user568458

# Makes the code works
if [[ "$r" == *"irt"* ]]; then
    echo "TEST"
fi

请注意,$r的定义是:

# Double quotes should fix it, right? Those special characters/multi-lines
r="$(ls)"

还要注意,一切都在循环内,循环成功。每次if比较匹配时都会出现问题,而不是打印发出的"TEST",直接跳到循环的下一次迭代(没问题:在这个if之后没有代码存在)。

我的问题是:为什么每次字符串匹配时都会发生错误?根据我的理解,双引号就足以解决它。此外,如果我依靠双方括号来修复它,一些shell将无法识别它(指的是上面提到的answer)。有什么选择?

Shell脚本似乎是一个全新的编程范例。我从来没有完全掌握细节,也无法找到一个很好的源代码。

linux bash shell double-quotes square-bracket
2个回答
5
投票

单个括号是内置的shell,而不是双括号,它是shell关键字。不同之处在于内置行为类似于命令:当shell解析命令时,会发生单词拆分,文件模式匹配等。如果你有与*irt*模式匹配的文件,比如file1irt.txtfile2irt.txt,那么当shell解析命令时

[ "$r" = *irt* ]

它扩展了$r,匹配匹配模式*irt*的所有文件,并最终看到命令:

[ expansion_of_r = file1irt.txt file2irt.txt ]

这会产生错误。没有引号可以解决这个问题。实际上,单括号形式根本无法处理模式匹配。

另一方面,双括号不像命令那样处理; Bash不会执行任何分词或文件模式匹配,所以它确实看到了

[[ "expansion_of_r" = *irt* ]]

在这种情况下,右侧是一个模式,因此Bash测试左侧是否与该模式匹配。


对于便携式替代方案,您可以使用:

case "$r" in
    (*irt*) echo "TEST" ;;
esac

但是现在你在这里有一个可怕的反模式。你在做:

r=$(ls)
if [[ "$r" = *irt* ]]; then
    echo "TEST"
fi

我的理解是你想知道是否有与当前目录中的模式*irt*匹配的文件。便携式可能性是:

for f in *irt*; do
    if [ -e "$f" ]; then
        echo "TEST"
        break
    fi
done

1
投票

由于您要检查具有特定文件名的文件,我建议明确使用find。就像是

r="$(find . -name '*irt*' 2> /dev/null)"
if [ ! -z "$r" ]; then
  echo "found: $r"
fi
© www.soinside.com 2019 - 2024. All rights reserved.