【问题标题】:Bash script error [: !=: unary operator expectedBash 脚本错误 [: !=: 应为一元运算符
【发布时间】:2014-03-04 17:55:47
【问题描述】:

在我的脚本中,我试图错误检查第一个也是唯一一个参数是否等于-v,但它是一个可选参数。我使用 if 语句,但我不断收到一元运算符预期的错误。

这是代码:

if [ $1 != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

更具体:

上面的这部分脚本正在检查一个可选参数,然后,如果没有输入参数,它应该运行程序的其余部分。

#!/bin/bash

if [ "$#" -gt "1" ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" = -v ]; then
   echo "`ps -ef | grep -v '\['`"
else
   echo "`ps -ef | grep '\[' | grep root`"
fi

【问题讨论】:

  • ...顺便说一句,我想你想要echo "usage: $0 [-v]"; $- 显示活动的 shell 选项标志,而不是当前脚本的名称。
  • 我的那部分是对的,我希望它显示当前脚本的名称。
  • 欢迎来到 stackoverflow,尤其是 bash 标签!查看tag wiki 以获取有用的工具和资源,例如shellcheck,它将指出(尽管并不总是解释)许多类似的问题。
  • @user3380240, $- 不是当前脚本的名称。 $0 是。
  • 抱歉,打错了。

标签: bash


【解决方案1】:

行情!

if [ "$1" != -v ]; then

否则,当$1 完全为空时,您的测试将变为:

[ != -v ]

而不是

[ "" != -v ]

...而!= 不是一元运算符(即,只能接受一个参数)。

【讨论】:

  • 或者,如果您不关心可移植性,您可以使用双括号,其中不需要引用变量扩展:if [[ $1 != -v ]]; then
  • @MikeHolt,确实——我在上面对这个问题的评论中提出了这一点。
  • @DanielDinnyes,如果IFS=1,那么[ $# -eq 1 ] 不会表现得那么好,而[ "$#" -eq 1 ] 即使在那时也表现得如预期。这是一个病态的案例,当然,但最好是在有选择的情况下编写没有它们的软件。
【解决方案2】:

或者对于看似猖獗的矫枉过正,但实际上过于简单......几乎涵盖了您的所有案例,并且没有空字符串或一元问题。

如果第一个参数是'-v',则执行条件ps -ef,否则在所有其他情况下抛出用法。

#!/bin/sh
case $1 in
  '-v') if [ "$1" = -v ]; then
         echo "`ps -ef | grep -v '\['`"
        else
         echo "`ps -ef | grep '\[' | grep root`"
        fi;;
     *) echo "usage: $0 [-v]"
        exit 1;; #It is good practice to throw a code, hence allowing $? check
esac

如果你不关心 '-v' 参数在哪里,那么只需将 case 放到一个循环中。这将允许遍历所有参数并在任何地方找到“-v”(只要它存在)。这意味着命令行参数顺序并不重要。请注意,如前所述,变量 arg_match 已设置,因此它只是一个标志。它允许多次出现“-v”参数。可以很容易地忽略所有其他出现的“-v”。

#!/bin/sh

usage ()
 {
  echo "usage: $0 [-v]"
  exit 1
 }

unset arg_match

for arg in $*
 do
  case $arg in
    '-v') if [ "$arg" = -v ]; then
           echo "`ps -ef | grep -v '\['`"
          else
           echo "`ps -ef | grep '\[' | grep root`"
          fi
          arg_match=1;; # this is set, but could increment.
       *) ;;
  esac
done

if [ ! $arg_match ]
 then
  usage
fi

但是,允许参数多次出现在以下情况下使用起来很方便:

$ adduser -u:sam -s -f -u:bob -trace -verbose

我们不关心参数的顺序,甚至允许多个 -u 参数。是的,这也很简单:

$ adduser -u sam -s -f -u bob -trace -verbose

【讨论】:

  • $* 不应在此上下文中使用:它将项目连接成一个字符串,该字符串既是字符串拆分又是全局扩展的;与"$@" 不同,它会为项目留下精确的原始值。你错过了一些引用,shellcheck.net 会捕捉到(警告链接到描述这些引用为何重要的 wiki 页面)。
  • 考虑,作为一个具体的例子,-U'Bob Barker'; for arg in $* 将其视为-UBob,然后将Barker 视为一个单独的项目;而for item in "$@" 会将-UBob Barker 视为单个字符串。
猜你喜欢
  • 2018-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-24
  • 1970-01-01
  • 2018-04-11
相关资源
最近更新 更多