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

时间:2012-12-08 19:46:25

标签: bash if-statement arguments

我找不到任何一个简单直接的资源,用于解释以下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 

6 个答案:

答案 0 :(得分:297)

如果$VARIABLE是包含空格或其他特殊字符的字符串and single square brackets are used(这是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/sh等调用的默认shell不兼容。这意味着在某些系统上,例如,它可能在控制台上运行但不是来自cron,具体取决于所有内容的配置方式。

看起来像这样:

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

还要注意[: unary operator expected错误

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

如果你习惯了其他语言,那就是'gotcha' - 你不希望变量的内容在评估之前有效地打印到代码中。

这是一个阻止[: 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也是如此})

答案 1 :(得分:10)

刚刚碰到这篇文章,通过获得相同的错误,尝试测试两个变量是否两个为空(或非空)。结果证明是compound comparison - 7.3. Other Comparison Operators - Advanced Bash-Scripting Guide;我想我应该注意以下几点:

  • 我用 -e 认为它首先意味着“空”;但这意味着“文件存在” - 使用-z来测试空的变量(字符串)
  • 需要引用字符串变量
  • 对于复合逻辑AND比较,要么:
    • 使用两个test&&个:[ ... ] && [ ... ]
    • 或在-a test中使用[ ... -a ... ]运算符:grep

这是一个工作命令(搜索目录中的所有txt文件,并转储那些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 找到包含两个单词的文件):

test

编辑2013年8月12日:相关问题说明:

请注意,在使用经典[(单方括号=)检查字符串相等性时,必须在“is equal”运算符之间有一个空格,在此处case是一个单独的“等于”==符号(虽然两个等于'符号$ 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

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

{{1}}

答案 2 :(得分:4)

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

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

如果您调用foo.shfoo.sh arg1,它将正常工作。但是,如果您传递多个foo.sh arg1 arg2之类的参数,则会出错。这是因为它正在扩展为[ -z arg1 arg2 ],这不是有效的语法。

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

答案 3 :(得分:2)

有时如果您意外触摸键盘并移除了空格。

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

将触发此错误消息。注意']'之前的空格。

答案 4 :(得分:2)

我也遇到了同样的问题。 @sdaau 的回答以合乎逻辑的方式帮助了我。在这里,我正在做的事情对我来说在语法上似乎是正确的,但是参数错误太多了。

错误的语法:

if [ $Name != '' ] && [ $age != '' ] && [ $sex != '' ] && [ $birthyear != '' ]  && [ $gender != '' ] 
then
    echo "$Name"
    echo "$age"
    echo "$sex"
    echo "$birthyear"
    echo "$gender"
else
    echo "Enter all the values"
fi

在上面的 if 语句中,如果我传递了下面提到的变量的值,那么我也会收到语法错误

export "Name"="John"
export "age"="31"
export "birthyear"="1990"
export "gender"="M"

使用以下语法,我得到了预期的输出。 正确的语法:

if [ "$Name" != ""  -a  "$age" != ""  -a  "$sex" != ""  -a  "$birthyear" != ""   -a  "$gender" != "" ] 
then
    echo "$Name"
    echo "$age"
    echo "$sex"
    echo "$birthyear"
    echo "$gender"
else
    echo "it failed"
fi

有几点需要注意

  1. 使用""代替''
  2. 使用 -a 代替 &&
  3. 在像[ a = b]这样的运算符号前后放置空格,不要在if条件中使用as [ a=b ]

因此上述解决方案对我有用!!!

答案 5 :(得分:1)

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

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;
这样我解决了我的问题。希望对你也有帮助。