引数とフラグをランダムな順序で取る関数を書くには?

引数とフラグをランダムな順序で取る関数を書くには?

私は最初にシェルに触れ、一般的な引数を受け入れ、提供されたすべてのフラグを解析するカスタム関数を書こうとしています。

test_it() {
  flag1="false"
  flag2="false"

  while getopts "ab" opt; do
    case ${opt} in
    a) flag1="true" ;;
    b) flag2="true" ;;
    *) break ;;
    esac
  done
  echo $flag1 $flag2
  shift "$(($OPTIND - 1))"
  echo "Custom param: $1"
}

ただし、この関数は、フラグの後にカスタムパラメータを指定した場合にのみ、私が望む方法で機能します。フラグの前にカスタムパラメータを指定すると、フラグは解析されません。

> test_it -ab foo
true true
Custom param: foo
> test_it foo -ab
false false
Custom param: foo
> test_it -a foo -b
true false
Custom param: foo

順序に関係なく、フラグとパラメータを正しく解析する方法はありますか?つまり、true true関数の呼び出し中に特定の時点で呼び出されるので、3つのケースすべてでこれら2つのフラグをエコーする必要がありますか?関数がこのようなことをするのを観察したので、これは可能でなければなりませんrsync

答え1

例:関数から呼び出す前に、while getopts以下を追加してください。

local OPTIND OPTARG

「カウンタ」は毎回ゼロにリセットされます。


また、これはwhile getopts最初の非オプションで停止します。動作するには、test foo -ab以下を使用する必要があります。getopt(1)getoptサンプルスクリプト)

test_it() {
    local tmp flag1=false flag2=false
    tmp=$(getopt -o 'ab' -n "$FUNCNAME" -- "$@")
    
    local rc=$?
    ((rc == 0)) || return $rc
    
    eval set -- "$tmp"
    
    while true; do
        case "$1" in
            '-a') flag1=true
                  shift
                  ;;
            '-b') flag2=true
                  shift
                  ;;
            '--') shift
                  break
                  ;;
            *)    echo Internal Error >&2
                  return 1
                  ;;
        esac
    done

    declare -p flag1 flag2
    echo "Remaining params:"
    printf "%s\n" "$@"
}
$ test_it foo -a bar -b
declare -- flag1="true"
declare -- flag2="true"
Remaining params:
foo
bar

$ test_it -a quz
declare -- flag1="true"
declare -- flag2="false"
Remaining params:
quz

$ test_it baz -b
declare -- flag1="false"
declare -- flag2="true"
Remaining params:
baz

$ test_it -c
test_it: invalid option -- c

$ test_it baz --ab
test_it: unrecognized option `--ab'

関連情報