쉘 스크립트에서 알 수 없는 매개변수를 추출하는 방법은 무엇입니까?

쉘 스크립트에서 알 수 없는 매개변수를 추출하는 방법은 무엇입니까?

다양한 옵션을 허용하는 쉘 스크립트가 있는데, 일부는 매개변수가 있고 일부는 매개변수가 없고 일부는 짧고 일부는 길다. 이러한 옵션 중 일부를 자체적으로 처리하고 나머지는 어떻게 관리해야 할지 모르는 다른 프로그램에 전달해야 합니다. getopts알 수 없는 매개변수를 저장하는 것과 유사한 것을 얻을 수 있습니까 ?

program예를 들어 내 스크립트가 호출되어 인수를 받아들여야 한다고 가정해 보겠습니다.

  • -n하나의 매개변수로,
  • --verbose논쟁의 여지가 없으며
  • -s논쟁의 여지가 없습니다.

모든 옵션과 해당 인수를 구문 분석하고 인쇄한 다음 echo rest:남은 항목을 호출합니다. 다음 출력을 관찰해야 합니다.

> program -sin42 --long --verbose
-s
-n with argument 42
--verbose
rest: -i --long 

> program -n --short
-n with argument --short

> program -n
error: -n without argument

쉘 스크립트에서 이와 같은 작업을 수행할 수 있습니까?

답변1

쉘에서 널리 사용되는 것은 물론이고 이를 수행하는 표준 방법도 없다고 생각합니다(즉, 처음부터 구현하는 것이 부족함).

매우 강력한 내장 기능을 ksh지원 하지만 . getopts이것(및 다소 까다로운 요구 사항)을 기반으로 ksh다음 코드 조각을 사용하여 가능한 기본 솔루션의 개요를 설명했습니다.

while getopts ":[-][[n]:][99:verbose][s]" opt
do  case $opt in
    (n) n_arg=$OPTARG ;;
    (99) verbose=1 ;;
    (s) s=1 ;;
    (*) arg_rest+=( "${@:OPTIND-1:1}" ) ;;
    esac
done
shift OPTIND-1

printf "main opt(%s)=%s\n" "-n" "$n_arg"
printf "main opt(%s)=%s\n" "--verbose" "$verbose"
printf "main opt(%s)=%s\n" "-s" "$s"

function delegate
{
    while getopts ":[-][i][98:long]" opt
    do  case $opt in
        (i) int=1 ;;
        (98) long=1 ;;
        esac
    done
    shift OPTIND-1

    printf "func opt(%s)=%s\n" "-i" "$int"
    printf "func opt(%s)=%s\n" "--long" "$long"
}

printf "Delegate: '%s'\n" "${arg_rest[@]}"
delegate "${arg_rest[@]}"

프로그램은 먼저 모든 옵션을 구문 분석하고 필요에 따라 내부 변수를 설정한 다음 알 수 없는 옵션을 배열에 저장합니다. 그러면 printf설정을 제어할 수 있는 몇 가지 옵션이 표시됩니다 . 그런 다음 나머지 옵션이 위임될 함수 정의가 제공되며 해당 함수는 명령으로 대체될 수도 있습니다. 마지막으로 나머지 매개변수를 사용하여 함수(또는 다른 명령)를 호출합니다.

ksh(함수에 대한 설명은 세션 getopts에서 호출하세요 .)kshgetopts --man

이 프로그램을 실행하면 다음과 같은 출력이 생성됩니다.

$ ksh ./getopts_script -s -n 23 --verbose -i --long
main opt(-n)=23
main opt(--verbose)=1
main opt(-s)=1
Delegate: '-i'
Delegate: '--long'
func opt(-i)=1
func opt(--long)=1



긴 옵션을 지원하는 getopts 함수의 셸 구현은 다음을 참조하세요.https://github.com/stephane-chazelas/misc-scripts/blob/master/getopts_long.sh

답변2

getopt이미 알려진 옵션을 선주문하는 것은 쉽습니다 . 안타깝게도 알 수 없는 모든 매개변수를 거부하고 구문 분석을 즉시 중지합니다.

그러나 긴 옵션이 지나치게 복잡하지 않은 한 bash를 속여서 getopts이 작업을 수행할 수 있습니다 . 어떤 영감은 다음에서 비롯됩니다.mkaurball. 출처 아래에 참고사항이 포함되어 있습니다.

#!/bin/bash

while [ $OPTIND -le $# ]
do
  if getopts ":sn:-:" argument
  then
    case $argument in
      s) echo "-$argument" ;;
      n) echo "-$argument with argument $OPTARG" ;;
      \?) pass+=("-$OPTARG") ;;
      -) lastarg=$((OPTIND - 1))
        case "${!lastarg}" in
          --verbose) echo "--verbose" ;;
          --*) pass+=("--$OPTARG") ;;
          *) echo "invalid argument: -"
            exit 1 ;;
        esac ;;
      :) echo "$OPTARG without argument"
        exit 1 ;;
    esac
  else
    pass+=("${!OPTIND}")
    let OPTIND++
  fi
done

echo pass: "${pass[@]}"
  • 일반적으로 getoptss는 조건으로 사용되지 않습니다 while. 이로 인해 위치 인수(즉, 옵션도 인수도 아닌 인수)를 만나자마자 루프가 중지됩니다. 대신 이러한 사례는 매개변수가 수집되는 배열에 추가됩니다 pass.
  • 매개변수 사양에는 긴 옵션이 매개변수가 있는 짧은 옵션으로 처리되도록 하는 :-가 포함됩니다 . 짧은 옵션 복합어(예를 들어)의 중간에 대시를 혼합하면 부주의하게 사용하면 이 문제가 발생할 수 있으므로 실제 인수가 실제로 두 개의 대시로 시작하는지 확인하는 것이 좋습니다. 따라서 래핑된 프로그램이 옵션을 옵션으로 처리하려는 경우 이 메서드는 실패합니다.getopts--long--long-s-n-short-with-dashes
  • 본질적으로 getopts이중 대시도 삼켜집니다. 이는 바람직할 수도 있지만 [ "${!OPTIND}" != '--' ] &&앞에 삽입하여 피할 수도 있습니다.getopts
  • 래퍼는 중첩된 매개변수 내에 있어야 하기 때문에 긴 매개변수를 구문 분석하는 데 약간의 어려움이 있을 수 있습니다 case.

관련 정보