bash [: 大于符号的参数过多

bash [: too many arguments greater than symbol

这不是一个真正的问题(尽管我在最后提出了一个问题),而是我想分享的一个问题的解决方案,以防它对其他人有所帮助。

我在打开新终端时得到 bash: [: too many arguments 的时间最长(特别是 OS X 上安装了 bash-completion macport 的 iTerm2。此错误源自文件 /opt/local/etc/bash_completion 中的行 if [ -n "$BASH_VERSION" -a -n "$PS1" -a -z "$BASH_COMPLETION_COMPAT_DIR" ]; then。我终于找到了问题所在,因为我的 .bash_profile 中有 export PS1='>'。将 PS1 更改为其他内容(例如 '> ')修复了 bash 完成的问题。

在 OS X 和 Debian 中进行的一些实验表明,在将额外的表达式(使用 -a-o)添加到测试 ([ ]) 之后会出现此问题涉及 '>' 的表达式。例如,

> A='>'; if [ -n "$A" ]; then echo "yes"; fi
yes
> A='>'; if [ -n "$A" -a -n "$A" ]; then echo "yes"; fi
bash: [: too many arguments
> A='> '; if [ -n "$A" -o -n "$A" ]; then echo "yes"; fi
yes
> A='>'; if [ -n "$A" -o -n "Hello" ]; then echo "yes"; fi
bash: [: too many arguments
> A='>'; if [ -n "Hello" -a -n "$A" ]; then echo "yes"; fi
yes

这是 bash 中的(已知)错误吗?

如果你想使用两个或多个条件,你应该使用

if [ condition1 ] && [condition2 ]

if [ condition1 ] || [condition2 ]

所以在你的情况下(首先是 if "and"):

A='>'; if [ -n "$A" ] && [ -n "$A" ]; then echo "yes"; fi

对于 "or" 如果:

A='>'; if [ -n "$A" ] || [ -n "Hello" ]; then echo "yes"; fi

但请注意,第二个检查 [ -n "Hello" ] 始终为真,因此最好将其删除。

您可能对 shellcheck 感兴趣,以验证您的 bash 脚本语法。

只要 $A 中存储的字符串不是 [ / test 识别的 运算符 ,您的解决方法就有效 -正如您所发现的,只需添加 space 就足够了。

Surely the "greater than" should be interpreted as just a string? It works with '> ' after all.

不,$A 的内容 而不是 被解释为只是一个字符串。 (如果你想要那样,你必须改用 [[,它是在特殊的上下文中解析的,更像你对传统编程语言的期望。)

[ (test) 是内置的(在大多数系统上也作为外部实用程序存在),因此使用 命令语法 进行解析意思是:

  • shell 执行其扩展 首先 - $A 在这种情况下,引用被替换为变量的内容。
  • 然后将结果传递给 [

因此,从 [ 的角度来看,它最终看到的运算符(在您的示例中为 >)是否来自 literal[ 并不重要=78=] 或存储在 变量中 .

但请注意whitespace很重要:传递>(没有spaces)被解释为运算符; >,相比之下,><space> 不是 - 因为确切的文字比运算符更多


底线是:

  • 您使用的 bash-完成脚本不可靠
  • 正如@chepner 在对该问题的评论中所述,POSIX recommends not using -o / -a 以避免您遇到的歧义(强调我的):

The XSI extensions specifying the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent. (Many expressions using them are ambiguously defined by the grammar depending on the specific expressions being evaluated.)

  • 具体来说,使用单独的 [ ... ] 表达式与 &&(而不是 -a)和 ||(而不是 -o ) 解决问题:

    [ -n "$BASH_VERSION" ] && [ -n "$PS1" ] && [ -z "$BASH_COMPLETION_COMPAT_DIR" ]
    

或者,更简单地说,利用计算结果为真的非空字符串:

[ "$BASH_VERSION" ] && [ "$PS1" ] && [ -z "$BASH_COMPLETION_COMPAT_DIR" ]

请注意,虽然 -a-o 引入了 歧义 ,但它们 不是 安全问题 - 你不能通过使用它们来注入任意代码。