【问题标题】:[ :Unexpected operator in shell programming [duplicate][ :Unexpected operator in shell programming [duplicate]
【发布时间】:2011-03-25 13:45:53
【问题描述】:

我的代码:

    #!/bin/sh
    #filename:choose.sh
    read choose
    [ "$choose" == "y" -o "$choose" == "Y" ] && echo "Yes" && exit 0
    [ "$choose" == "n" -o "$choose" == "N" ] && echo "No"  && exit 0
    echo "Wrong Input" && exit 0

但是当我执行时

    sh ./choose.sh

终端提示我

   [: 4: n: :Unexpected operator
   [: 5: n: :Unexpected operator

我的 bash 脚本有什么错误吗? 谢谢!

【问题讨论】:

  • 当我在 Linux 和 cygwin 中执行相同的代码时,我没有收到任何错误
  • Cygwin 很可能将 sh 别名为 bash。有些发行版不再提供真正的sh。尽管有些人会争辩(我倾向于同意),如果您要编写可移植的脚本,请将其写入 sh 而不是 bash
  • 我的问题是我需要source foobar.sh 而不是./foobar.sh
  • 两个错误:1.使用“=”而不是“== for /bin/sh 2.不处理空字符串。做 ${choose}BLAH == yBLAH 来解决这个问题。所以这在技术上也不是一个重复的问题。
  • @personal_cloud,请不要推荐${choose}BLAH 方法——最好只引用"$choose";自 1970 年代以来就不再需要常量前缀/后缀(只要避免在当前 POSIX test 标准中标记为过时的功能,如 -a-o)。

标签: linux bash shell


【解决方案1】:

您的 bash 脚本没有错误。但是您使用 sh 执行它,它的语法不太广泛;)

所以,请运行 bash ./choose.sh :)

【讨论】:

  • bash 语法是sh 语法的超集 - 您系统上的/bin/sh 可执行文件可能只提供标准的sh 功能,其中不包括[] 样式的测试。
  • 是的。它们是完全不同的壳。尽管 bash 基于 sh 并且在很大程度上向后兼容,并且它们实际上可能是您系统上的同一个程序,但仍然会根据您使用的名称而有所不同。您可以通过将第一行更改为#!/bin/bash 并使文件可执行,然后运行./choose.sh 来自动使用bash 运行脚本。
  • 这个答案部分错误。完全正确的是尼采-茹现在投票最多的。 sh 支持 [== 适用于 Bash 内置插件 [[test[,而 a single = is required by POSIX version of [ and test。 (Bash 手册也这么说,顺便说一句。)因此要求 Bash 对可移植性是不必要的损害。命令名称是[test] 只是不必要的,未使用的最后一个参数。许多 shell 将这些实现为内置函数,as Wikipedia says
  • @Palec:虽然答案不如 Nietzche-jou ​​的答案广泛,但我看不出有什么问题?我从来没有提到任何关于括号的事情:)无论如何,+1 为您的评论!
  • @Wolph 写的部分错误我的意思是两件事。首先,问题不在于 Bash vs sh 语法,两者都可以正确调用[ 命令。它在[ 命令参数的语法中,这不是 sh 的业务。其次,对于这样的工作,Bash 是多余的,尤其是当存在更简单的解决方案时。这并不是真正的错误,因为它也解决了问题,但我认为这通常是不好的建议。这导致初学者得出错误的结论,即 Bash 解决了他们的问题。它在 POSIX 所需的功能上具有许多不可移植的扩展。我认为我们应该引导初学者编写可移植的程序。
【解决方案2】:

POSIX sh 不理解 == 的字符串相等性,因为那是 bash-ism。请改用=

其他人说 sh 不支持括号是错误的,顺便说一句。

【讨论】:

  • 是的,我尝试将“==”替换为“=”,脚本也可以通过“sh ./choose.sh”执行。bash和sh都支持括号。
  • +1 这比不必要地使用 bash,IMO 更好。
  • 在我的具体情况下,我的 Teamcity 代理默认运行 sh,我不想更改它(它会产生其他问题)。这里需要SH,我认为这对于必须使用sh的人来说是正确的答案
  • +1 这是正确的答案。任何想为 sh 解决它的人都应该使用单个 '='。只阅读 Wolph 投票率最高的回复就浪费了我 3 个小时 :(
  • 仍然是一个非常有价值的提示。很多 docker 镜像都有 sh 而没有 bash。
【解决方案3】:

要使用 Bash 执行它,请使用 #!/bin/bash 并 chmod 使其可执行,然后使用

./choose.sh

【讨论】:

    【解决方案4】:

    你可以用 case/esac 代替 if/else

    case "$choose" in
      [yY]) echo "Yes" && exit;;
      [nN]) echo "No" && exit;;
      * ) echo "wrong input" && exit;;
    esac
    

    【讨论】:

      【解决方案5】:

      你必须改用 bash 或使用标准 sh 重写你的脚本

      sh -c 'test "$choose" = "y" -o "$choose" = "Y"'
      

      【讨论】:

      • 我认为使用“[ ]”而不是“test”更方便。看来“bash ./choose.sh”可以解决问题。
      • @kit 不管怎样,sh 更便携
      • @kit.yang 括号怎么用更方便?由于人们没有意识到 [ 是 test 的同义词而造成的历史混乱,并且通过省略括号周围的空格而导致的持续错误几乎无法弥补保存的单个字符。 (“如果 [ $x = 5 ]”与“如果测试 $x = 5”;13 个字符与 14 个字符)。
      【解决方案6】:

      实际上,“[”方括号只是测试命令的内部 shell 别名。

      所以你可以说:

      test -f "/bin/bash" && echo "This system has a bash shell"
      

      [ -f "/bin/bash" ] && echo "This system has a bash shell"
      

      ...它们在 sh 或 bash 中是等效的。请注意在“[”命令上必须有一个右括号“]”,但除此之外“[”与“test”相同。 “man test”是一本好书。

      【讨论】:

      • man test 是 /bin/test 的手册页,不适用于内置 shell 函数
      • ls $(which [)/usr/bin/[
      • 对我不起作用。
      【解决方案7】:

      不要使用任何保留关键字作为任何变量名的开头: 例如,HOSTNAME 将失败,因为 HOST {TYPE|NAME} 已保留

      【讨论】:

        猜你喜欢
        • 2012-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-21
        • 2020-05-15
        • 1970-01-01
        • 2020-09-04
        相关资源
        最近更新 更多