代码之家  ›  专栏  ›  技术社区  ›  user1874594

如何在shell中使用互斥标志并添加可选参数标志(使用getopts)

  •  3
  • user1874594  · 技术社区  · 12 年前

    我使用的是标准的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
    

    如何强制执行互斥标志。我相信有更多的杂技演员的方法可以做到这一点。我想我在这里缺少了一些常识——并试图弄清楚这一点。 谢谢

    $ 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等待您的回复。 我想添加一个额外的标志-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
    

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

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

    再次感谢

    3 回复  |  直到 12 年前
        1
  •  3
  •   user743382 user743382    12 年前

    下面是如何在不将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 听起来不应该继续)。 返回1 只会使 死亡 函数返回失败,但调用 死亡 不要检查它的结果,它会继续下去。
    • 这个 getopts 字符串为 :ab 而不是 :a:b: 。无论您如何调用脚本,无论选项如何,始终需要传递一个SID,因此将其作为选项的一部分对我来说没有意义。
    • 选项以布尔形式存储 opta 和 optb 便于检查的变量
    • 传递所有选项后,将对剩余的命令行参数进行计数。除非它正好是一个,否则对脚本的调用是无效的。

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

        2
  •  3
  •   Wildcard    9 年前

    如果你 必须 只指定一个选项 -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 , i 或 h 为了简化说明,省略了参数。

    脚本的概要如下:

    $0 [ -v ] [ -n ] { -i IPADDRESS | -h HOSTNAME | -s HOSTSHA }
    
        3
  •  2
  •   John1024 David C. Rankin    12 年前

    这使得选项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语句后的前两行处理。

    推荐文章