繁体   English   中英

如何在shell中使用互斥标志并添加一个可选的参数标志(卡住了getopts)

[英]How to use mutually exclusive flags in your shell and add an optional argument flag ( stuck with getopts)

我正在使用标准的getopts逻辑。 但我想知道如何制作我提供的选项 - 互相排斥。 例如

shell.sh -a SID 
                              <accepted>
shell.sh -b SID
                              <accepted>
shell.sh -ab SID 
               Message- using ab together is the same as running shell.sh     without   any   options supplying  just SID . Help usage < ya da ya > 
shell.sh 
                Please enter SID at the minimum. Usage < ya da ya >
shell.sh SID
               <accepted>

我试图用下面的东西来开发这个逻辑

while getopts ":a:b:" opt; do
  case $opt in
  a ) SID="$OPTARG";;
      set var=1
  b ) SID="$OPTARG";;
      set var=2

 \?) echo "Invalid option: -"$OPTARG"" >&2
        exit 1;;
  ) echo "Option -"$OPTARG" requires an argument." >&2
        exit 1;;
  esac
done

If  (( val == 1 ))  then ; # option a is invoked SID supplied 
<stuff>
elif  (( val == 2 )) then ; # option b is invoked SID supplied 

<stuff>

else # SID supplied but neither a or b is invoked 
<stuff>
fi

如何强制执行互斥标志。 我确信有更多的acrobat方法可以做到这一点。 我想我在这里错过了一些常识 - 并试图解决这个问题。 谢谢

$ more opt.ksh
die () {
    echo "ERROR: $*. Aborting." >&2
    return  1
}

var=
while getopts ":a:b:" opt; do
  case $opt in
      a ) SID="$OPTARG"
          [ "$var" = 2 ] && die "Cannot specify option a after specifying option b"
          [ "$OPTARG" = b ] && die "Do not specify b as a value for option a"
          var=1
          ;;
      b ) SID="$OPTARG"
          [ "$var" = 1 ] && die "Cannot specify option b after specifying option a"
          [ "$OPTARG" = a ] && die "Do not specify a as a value for option b"
          var=2
          ;;
      :)  die "Must supply an argument to $OPTARG"
          ;;
      \?) die "Invalid option: -$OPTARG. Abort"
          ;;
  esac
done
shift $(($OPTIND - 1))
[ "$SID" ] || SID=$1
[ "$SID" ] || die "You must, at the minimum, supply SID"

我正在使用ksh

$ ps -p $$
  PID TTY          TIME CMD
 1261 pts/45   00:00:00 ksh

我第一次跑它。

$ . opt.ksh -a 123 -b 123  # c0
ERROR: Cannot specify option b after specifying option a. Aborting.
-bash: /home/d1ecom1/gin1: No such file or directory


$ . opt.ksh -ab 123  # c1 should reject "cant use a and b togather. try with a or b"
-nologin: .[25]: shift: 4: bad number
$ . opt.ksh -a -b  # c2  same as c1's message
$ . opt.ksh -a -b 123 # c3 same as c1

$ . opt.ksh -a -b 123  # c5 
$ . opt.ksh -ab 123    # c6
$ . opt.ksh -a 123 -b 123  # c7

以上所有情况C0:C7都应该拒绝。 注意C0和C7是相同的。 然而,尽管这个C0给出了预期的错误,C7不会给出任何错误? 奇怪

只有工作的人才应该

. opt.ksh -a 123
. opt.ksh -b 123
. opt.ksh  123

@hvd:TYSM的回复。 我想添加一个additonal标志-p,它将提供一个“路径覆盖”选项。 所以也许我们必须扩展getopt以获取这样的参数

    die () {
    echo "ERROR: $*. Aborting." >&2
    exit 1
}

var=
opta=false
optb=false
while getopts ":ab:p" opt; do
  case $opt in
      a ) $optb && die "Cannot specify option a after specifying option b"
          opta=true
          ;;
      b ) $opta && die "Cannot specify option b after specifying option a"
          optb=true
          ;;
      p )  [ -d "$mypath" ] && die "path is invalid"

          ;;

      \?) die "Invalid option: -$OPTARG. Abort"
          ;;
  esac
done
shift $(($OPTIND - 1))
test $# -eq 0 && die "You must supply SID"
test $# -eq 1 || die "Too many command-line arguments"
# SID=$1

以上是旧方法。 现在我有2个输入参数。 一个是SID,另一个是路径。 它是否像上面那样简单,或者我是否需要添加更多检查以防止其他不需要的组合。 我想我试图瞄准的问题是,需要做出更多规定来允许这个-p参数,这是一个optiona覆盖参数。 - p可以与上面的任何参数共存,但我猜一个要求是它应该紧跟在-p标志之后,所以这不应该允许 - 因为它不清楚。

shell.sh -b -p 123 /home/yadaya

再次感谢

这使得选项a和b互斥:

die () {
    echo "ERROR: $*. Aborting." >&2
    exit 1
}

var=
while getopts ":a:b:" opt; do
  case $opt in
      a ) SID="$OPTARG"
          [ "$var" = 2 ] && die "Cannot specify option a after specifying option b"
          [ "$OPTARG" = b ] && die "Do not specify b as a value for option a"
          var=1
          ;;
      b ) SID="$OPTARG"
          [ "$var" = 1 ] && die "Cannot specify option b after specifying option a"
          [ "$OPTARG" = a ] && die "Do not specify a as a value for option b"
          var=2
          ;;
      :)  die "Must supply an argument to $OPTARG"
          ;;
      \?) die "Invalid option: -$OPTARG. Abort"
          ;;
  esac
done
shift $(($OPTIND - 1))
[ "$SID" ] || SID=$1
[ "$SID" ] || die "You must, at the minimum, supply SID"

请注意,optargs将shell.sh -ab SID解释为选项a其中参数b后跟SID作为脚本的参数,而不是选项的一部分。 为了检测这个问题,上面涉及[ "$OPTARG" = b ] && die...[ "$OPTARG" = a ] && die...被添加。

您希望接受没有指定选项的shell.sh SID 这由case语句之后的前两行处理。

以下是如何在不使SID成为选项参数的情况下执行此操作,这对我来说更有意义:

die () {
    echo "ERROR: $*. Aborting." >&2
    exit 1
}

var=
opta=false
optb=false
while getopts ":ab" opt; do
  case $opt in
      a ) $optb && die "Cannot specify option a after specifying option b"
          opta=true
          ;;
      b ) $opta && die "Cannot specify option b after specifying option a"
          optb=true
          ;;
      \?) die "Invalid option: -$OPTARG. Abort"
          ;;
  esac
done
shift $(($OPTIND - 1))
test $# -eq 0 && die "You must supply SID"
test $# -eq 1 || die "Too many command-line arguments"
SID=$1

我所做的改变是:

  • return 1变为exit 1 (与您的问题无关,但die听起来不应该继续)。 return 1只会使die函数返回非成功,但是对die的调用不会检查它的结果,它会继续执行。
  • getopts字符串是:ab而不是:a:b: . 无论您如何调用脚本,无论选项如何,您总是需要传递一个SID,因此将其作为选项的一部分包含在内是没有意义的。
  • 选项存储在boolean optaoptb变量中,以便于检查
  • 传递所有选项后,将计算剩余的命令行参数。 除非它只是一个,否则对脚本的调用无效。

您接受问题中的所有有效呼叫,拒绝所有无效呼叫。 但有一点值得关注:您的测试用例c7( -a 123 -b 123 )预计会失败,并且会失败,但不会因为-a-b的组合而失败。 相反,在我的方法中,因为-b出现在非选项参数之后,它本身是一个非选项参数,拒绝它的原因变成“太多的命令行参数”。

对于必须指定选项-s-i-h一个选项的情况,以及另外两个选项-v-n是可选的,您可以执行以下操作:

modes=0
while getopts :vs:i:h:n opt; do
  case "$opt" in
    v)
      verbose='non-empty-string-true-flag'
      ;;
    s)
      ((modes++))
      : do something with OPTARG, the s form
      ;;
    i)
      ((modes++))
      : do something with OPTARG, the i form
      ;;
    h)
      ((modes++))
      : do something with OPTARG, the h form
      ;;
    n)
      dryrun='non-empty-string-true-flag'
      ;;
    :)
      printf 'Option -%s requires an argument\n' "$OPTARG" >&2
      usage
      exit 1
      ;;
    *)
      printf 'Invalid option: -%s\n' "$OPTARG" >&2
      usage
      exit 1
      ;;
  esac
done
shift "$((OPTIND-1))"
if [ "$modes" -eq 0 ]; then
  printf "Missing required option\n" >&2
  usage
  exit 1
elif [ "$modes" -gt 1 ]; then
  printf "Error: -h, -i and -s are mutually exclusive and may only be used once\n" >&2
  usage
  exit 1
fi

这是从我的脚本中摘录s ,为了简化说明,省略了对sih参数的处理。

脚本的概要如下:

$0 [ -v ] [ -n ] { -i IPADDRESS | -h HOSTNAME | -s HOSTSHA }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM