258

我找不到任何一个简单直接的资源来说明以下 BASH shell 错误的含义并对其进行修复,因此我在研究后发布了我发现的内容。

错误:

-bash: [: too many arguments

谷歌友好版本: bash open square bracket colon too many arguments .

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

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

6 回答 6

423

如果您$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 不兼容。

这意味着在某些系统上,它可能从控制台工作,但在其他地方调用时不能工作,例如 fromcron,这取决于所有内容的配置方式。

它看起来像这样:

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

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


还要注意[: unary operator expected错误

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

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

这是一个防止 the[: 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

于 2012-12-08T19:46:25.290 回答
15

刚刚碰到这篇文章,遇到同样的错误,试图测试两个变量是否都是空的(或非空的)。结果证明这是一个复合比较 - 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 日编辑:相关问题说明:

请注意,在使用经典test(单个方括号[)检查字符串相等性时,“等于”运算符之间必须有一个空格,在这种情况下,它是一个“等号”=符号(尽管两个等号==似乎被接受为相等运营商也是)。因此,这失败了(默默地):

$ 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
于 2013-05-28T10:36:36.557 回答
6

[: too many arguments您可能会遇到or错误的另一种情况[: 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 ]. ($#是参数的数量)。

于 2019-08-06T23:07:49.910 回答
5

我也面临同样的问题。@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 条件中用作 [ a = b ]

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

于 2021-06-02T15:29:43.340 回答
4

有时如果您不小心触摸键盘并删除了一个空格。

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

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

于 2018-06-07T16:47:18.160 回答
1

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

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

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

于 2017-06-17T16:03:35.170 回答