if [](方括号)中的“ [:过多参数”错误的含义


211

我找不到任何简单易懂的资源来说明BASH shell错误的含义并修复此错误,因此,我将发布研究后发现的内容。

错误:

-bash: [: too many arguments

Google友好版本: bash open square bracket colon too many arguments

上下文:单个方括号中的if条件,带有简单的比较运算符,例如equals,大于等,例如:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 

1
产生此特定错误的代码在哪里?
安德森·格林

Answers:


353

如果您$VARIABLE的字符串是包含空格或其他特殊字符的字符串,并且使用了一个方括号(这是该test命令的快捷方式),则该字符串可能会分成多个单词。这些每个都被视为一个单独的参数。

因此,一个变量被分成许多参数

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

对于放下包含空格或其他特殊字符的字符串的任何函数调用,也是如此。


容易修复

将变量输出用双引号引起来,强制其保留为一个字符串(因此为一个参数)。例如,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

就那么简单。但是,如果您也不能保证您的变量不会是一个空字符串,或者除了空格之外就什么都不是的字符串,请跳到下面的“也要当心...”。


或者,另一种解决方法是使用双方括号(这是该new test命令的快捷方式)。

但是,它仅存在于bash(显然是korn和zsh)中,因此可能与/bin/shetc 调用的默认shell不兼容。

这意味着在某些系统上,它可能可以在控制台上运行,但在其他地方(例如从)调用时则不能cron,这取决于所有配置方式。

它看起来像这样:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

如果您的命令包含这样的双方括号,并且您在日志中遇到错误,但可以从控制台运行,请尝试将换成[[此处建议的替代方法,或者确保运行脚本的任何东西都使用支持[[aka 的外壳new test


还要提防[: unary operator expected错误

如果看到“参数过多”错误,则很可能是您从函数中获得了一个字符串,该字符串具有不可预测的输出。如果还可以获取一个空字符串(或所有空白字符串),则即使使用上述“快速修复”,也将其视为零参数,并且将失败[: unary operator expected

如果您习惯于其他语言,则这是相同的“陷阱”-您不希望变量的内容在评估之前像这样被有效地打印到代码中。

这是一个防止[: too many arguments[: unary operator expected错误的示例:如果输出为空(在此示例中为0),则用默认值替换输出,并用双引号引起来:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(此处,如果$ VARIABLE为0或为空,则将执行该操作。自然地,如果需要不同的行为,则应将0(默认值)更改为其他默认值)


最后说明:由于[是的快捷方式test,因此上述所有错误均适用test: too many arguments(并且也适用test: unary operator expected


更好的方法是i=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So

1
我遇到了一个问题,当通过终端执行时,使用BASH作为解释器的Shellscript可以正常运行,但是当通过Crontab执行时,却出现了这样的故障,并通过Postfix发送本地电子邮件,通知了此错误,我发现,存在具有特殊字符的变量的IF。双引号挽救了我的命。谢谢 :)!
ivanleoncz

13

通过遇到相同的错误,试图测试两个变量是否都为空(或非空),这才刚刚进入这篇文章。事实证明这是一个复合比较-7.3。其他比较运算符-高级Bash脚本编写指南;我认为我应该注意以下几点:

  • 我曾经-e以为一开始它意味着“空”。但这意味着“文件存在”- -z用于测试空变量(字符串)
  • 字符串变量需要加引号
  • 对于复合逻辑AND比较,可以:
    • 使用两个tests和&&它们:[ ... ] && [ ... ]
    • -a单独使用运算符test[ ... -a ... ]

这是一个有效的命令(搜索目录中的所有txt文件,并转储grep包含两个单词的文件):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

编辑2013年8月12日:相关问题注释:

请注意,当用classic test(单方括号[)检查字符串是否相等时,“ is equal”运算符之间必须有一个空格,在这种情况下,它是单个“ equals” =符号(尽管两个equals的符号==似乎被视为相等)运营商)。因此,这将失败(无提示):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

...但是增加空间-一切看起来都不错:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B

您能提供一个bash shell示例((A || B) && C)吗?
jww

请参阅问题382642514964805
splaisan '16

这实际上对回答没有什么用,因为它没有显示如何将命令完全包含在方括号内,例如,如果存在循环,则需要此命令。
蒂莫西·斯旺

5

您可能会遇到[: too many arguments[: a: binary operator expected错误的另一种情况是,如果您尝试测试所有参数"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

如果您致电foo.sh或,它可以正常工作foo.sh arg1。但是,如果您传递多个参数,例如foo.sh arg1 arg2,则会出错。这是因为它被扩展为[ -z arg1 arg2 ],这不是有效的语法。

检查参数是否存在的正确方法是[ "$#" -eq 0 ]。($#是参数的数量)。


2

有时候,如果您不小心触摸了键盘并移走了一个空格。

if [ "$myvar" = "something"]; then
    do something
fi

将触发此错误消息。请注意“]”前的空格。


1
我认为这会导致不同的语法错误,例如:第21行:[:缺少`]'
Joe Holloway,

1

我的脚本遇到了同样的问题。但是,当我做一些修改时,它对我有用。我确实是这样:-

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

这样我就解决了我的问题。希望对您也有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.