쉘 스크립트에서 -a -b와 같은 옵션을 처리하지만 --abc?를 유지합니까?

쉘 스크립트에서 -a -b와 같은 옵션을 처리하지만 --abc?를 유지합니까?

그래서 몇 가지 준비 작업을 수행한 다음 유틸리티를 실행하는 쉘 스크립트가 있습니다.

-a준비는 스위치에 의해 영향을 받거나 스위치를 기다릴 수 있습니다 -n. 이러한 스위치가 아닌 명령줄 내용은 유틸리티로 전달됩니다. 현재 내 스크립트는 다음과 같습니다

while getopts ":an" opt; do
  case $opt in
    a)
      #something
      ;;
    n)
      #something else
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done
shift $((OPTIND-1))
  #more prep
my_utility $@

--abc그러나 로 해석되는 getopts ab옵션 과 같은 긴 형식 옵션을 유틸리티에 전달하려는 경우에는 실패합니다 .c

-a그렇다면 옵션 중 하나가 -n처리되지만 --abc변경되지 않는 방식으로 옵션을 처리하려면 어떻게 해야 합니까 ? 물론 쉘을 덤프하고 Python에서 실행하지 않는 한 옵션은 매우 간단하지만 파일을 복사하고 유틸리티를 실행해야 하는데 Python이 이를 어색하게 만듭니다.

답변1

이중 대시 명령을 해석하려면 내장 getoptgetopts.

내장된 bash를 사용하여 긴 옵션을 에뮬레이트하는 방법이 있지만 getopts패치워크이므로 그렇게 해서는 안 되고 getopts그렇게 할 수 없기 때문에 노력할 가치가 없습니다.구현하다긴 형식.

따라서 스크립트는 다음과 같습니다.

#!/bin/bash

# Get options
OPTS=`getopt --options an: --long a_something,n_something_else: -n 'parse-options' -- "$@"`

if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi

#echo parsed and cleaned up options
echo "$OPTS"
eval set -- "$OPTS"

bSomething=false
bSomethingElse=false

# "Endless" loop over the parsed options
while true; do
  case "$1" in
    -a | --a_something )       bSomething=true;     shift ;;
    -n | --n_something_else )  bSomethingElse=true; shift ;;
    -- )                                            shift; break ;;
    * )                                                    break ;;
  esac
done

더 많은 정보를 알고 싶다면:man getopt
자세한 내용은:man getopt(3)

답변2

-인수를 취하는 짧은 옵션으로 처리하여 긴 옵션을 에뮬레이트 할 수 없는 이유를 이해할 수 없습니다 .

$ cat /tmp/foo
while getopts :aq:-: opt; do
        case $opt in
        a)      echo option -a;;
        q)      echo option -q with value "$OPTARG";;
        -)      case $OPTARG in
                abc)    echo option --abc;;
                def=*)  echo option --def with value "${OPTARG#*=}";;
                *)      echo >&2 "unknown option --$OPTARG";;
                esac;;
        :)      echo >&2 "-$OPTARG needs an argument";;
        *)      echo >&2 "unknown option -$OPTARG";;
        esac
done
shift "$((OPTIND - 1))"
echo argv: "$@"

$ sh /tmp/foo -a -qt --abc --def=ghi -- foo bar
option -a
option -q with value t
option --abc
option --def with value ghi
argv: foo bar

인수 목록을 생성하고(예: 이를 사용하여 다른 명령 호출) 쉘이 배열을 지원하지 않는 경우(예: debian 또는 busybox /bin/sh) 다음 트릭을 사용할 수 있습니다. 실제 문자 문자열입니다. 이렇게 하면 IFS 분할/와일드카드/공백으로 인한 불편함을 피할 수 있습니다.

$ cat /tmp/foo
# handle -a and -qval
# call another command with any long options and non-option arguments
av=
while getopts :aq:-: opt; do
        case $opt in
        a)      echo option -a;;
        q)      echo option -q with value "'$OPTARG'";;
        -)      av="$av \"\${$((OPTIND-1))}\"" ;; # pass long options unchanged
        :)      echo >&2 "-$OPTARG needs an argument";;
        *)      echo >&2 "unknown option -$OPTARG";;
        esac
done
i=$OPTIND; while [ "$i" -le "$#" ]; do av="$av \"\${$i}\"" i=$((i + 1)); done

print_its_args(){ for a; do printf ' {%s}' "$a"; done; echo; }
echo "print_its_args $av"
eval "print_its_args $av"

그 다음에:

$ sh /tmp/foo -aqval --foo='a  **  b' --abc -- '(moo)'
option -a
option -q with value 'val'
print_its_args  "$2" "$3" "$5"
 {--foo=a  **  b} {--abc} {(moo)}

이 기술은 다른 곳에서도 사용될 수 있습니다상태;하지만 이 경우에는 set -- "$@" argargs를 밀어넣는 것과 같은 더 간단한 솔루션을 사용할 수 없습니다.$@개정하다 $@루프 내에서는 getopts이식 가능한 방식으로 수행할 수 없습니다 .

관련 정보