getopt, getopts 또는 manual parsing-short 및 long 옵션을 모두 지원하려면 어떻게해야합니까?


32

현재 다음 요구 사항이있는 Bash 스크립트를 작성 중입니다.

  • 다양한 유닉스 / 리눅스 플랫폼에서 실행되어야합니다
  • 단기 및 (GNU) 장기 옵션을 모두 지원해야합니다.

그 알 getopts은 긴 옵션을 지원하지 않는 휴대하지만 AFAIK의 측면에서 선호하는 방법이 될 것입니다.

getopt긴 옵션을 지원하지만 BashGuide 는 강력하게 권장합니다.

getopt (1)를 사용하지 마십시오. getopt는 빈 인수 문자열 또는 공백이 포함 된 인수를 처리 할 수 ​​없습니다. 그것이 존재했음을 잊지 마십시오.

따라서 수동 구문 분석 옵션이 여전히 있습니다. 이것은 오류가 발생하기 쉽고 보일러 코드를 생성하며 직접 오류를 처리해야합니다 ( getopt(s)오류 처리는 자체적으로 추측 합니다).

그렇다면이 경우 선호되는 선택은 무엇입니까?


답변:


9

다양한 Unices에 이식 할 수 있어야한다면 POSIX sh를 고수해야합니다. 그리고 AFAIU는 당신이 손으로 롤링 인수 처리를 할 수 밖에 없습니다.


25

getoptvs getopts는 종교적인 문제인 것 같습니다. Bash FAQgetopt 에서 반대 의견에 대해서는 :

  • " getopt빈 인수 문자열을 처리 할 수 ​​없습니다 " 는 선택적 인수 에 대한 알려진 문제를 나타내는 것으로 보이며, 이는 getopts전혀 지원하지 않는 것처럼 보입니다 (적어도 help getoptsBash 4.2.24의 읽기 에서). 보낸 사람 man getopt:

    getopt (3)은 빈 선택적 인수가 제공되는 선택적 인수로 긴 옵션을 구문 분석 할 수 있지만 짧은 옵션의 경우에는이를 수행 할 수 없습니다. 이 getopt (1)은 비어있는 선택적 인수를 존재하지 않는 것처럼 처리합니다.

" getopt공백 된 공백이있는 [...] 인수를 처리 할 수 ​​없습니다 " 는 어디에서 왔는지 모르지만 테스트 해 보겠습니다.

  • test.sh :

    #!/usr/bin/env bash
    set -o errexit -o noclobber -o nounset -o pipefail
    params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")"
    eval set -- "$params"
    
    while true
    do
        case "$1" in
            -a|--alpha)
                echo alpha
                shift
                ;;
            -b|--bravo)
                echo "bravo=$2"
                shift 2
                ;;
            -c|--charlie)
                echo charlie
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Not implemented: $1" >&2
                exit 1
                ;;
        esac
    done
  • 운영:

    $ ./test.sh -
    $ ./test.sh -acb '   whitespace   FTW   '
    alpha
    charlie
    bravo=   whitespace   FTW   
    $ ./test.sh -ab '' -c
    alpha
    bravo=
    charlie
    $ ./test.sh --alpha --bravo '   whitespace   FTW   ' --charlie
    alpha
    bravo=   whitespace   FTW   
    charlie

나에게 확인하고 친구처럼 보이지만 누군가 내가 어떻게 문장을 완전히 오해했는지 보여줄 것입니다. 물론 이식성 문제는 여전히 유효합니다. Bash가 오래되었거나없는 플랫폼에 투자 할 가치가있는 시간을 결정해야합니다. 내 팁은 YAGNIKISS 지침 을 사용하는 것입니다. 사용할 예정인 특정 플랫폼에 대해서만 개발하십시오. 개발 시간이 무한대로 진행됨에 따라 셸 코드 이식성은 일반적으로 100 %에 이릅니다.


11
OP는 많은 유닉스 플랫폼으로 이식 할 수 있어야한다고 언급했지만 getopt여기서 인용하는 것은 리눅스마다 다르다. 의 getopt일부는 아니며 bashGNU 유틸리티도 아니며 Linux에서는 util-linux 패키지와 함께 제공됩니다.
Stéphane Chazelas

2
대부분의 플랫폼에는 getoptLinux AFAIK 만 있고 긴 옵션 또는 공백을 인수로 지원하는 플랫폼이 있습니다. 다른 것들은 System V 구문 만 지원합니다.
Stéphane Chazelas

7
getoptLinux가 출시되기 오래 전에 System V에서 온 전통적인 명령입니다. getopt결코 표준화되지 않았습니다. POSIX, Unix 또는 Linux (LSB) 중 어느 것도이 getopt명령을 표준화하지 않았습니다 . getopts긴 옵션을 지원하지 않고 세 가지 모두에 지정됩니다.
Stéphane Chazelas

1
이 토론에 추가하기 만하면 이것은 전통적인 것이 아닙니다 getopt. @ StéphaneChazelas가 나타내는 linux-utils 풍미입니다. 위에 설명 된 구문을 비활성화하는 레거시 옵션, 특히 맨 페이지 상태 "GETOPT_COMPATIBLE은 get SYNOPSIS에 지정된 첫 번째 호출 형식을 사용하도록합니다." 이 패키지는 원래 getopt는 끔찍한이며, 배쉬의 getopt는 매우 제한 될 때이 완전히 길을 가야하는 것입니다 설치되어 대상 시스템을 기대할 수 그러나 경우
n.caillou

1
"전통 버전의 getopt는 빈 인수 문자열 또는 공백이 포함 된 인수를 처리 할 수 ​​없습니다"라고 주장하는 OP의 링크. 그리고 util-linux 버전의 getopt를 사용해서는 안된다는 증거가 없으며 더 이상 정확하지 않습니다. 빠른 조사 (5 년 후)에 따르면 ArchLinux, SUSE, Ubuntu, RedHat, Fedora 및 CentOS (및 대부분의 파생 변형)에서 사용할 수있는 기본 버전의 getopt는 모두 공백과 함께 선택적 인수와 인수를 지원합니다.
mtalexan

10

getopts_long 은 스크립트에 임베드 할 수있는 POSIX 쉘 함수로 작성되었습니다.

Linux getopt(from util-linux)는 기존 모드가 아니고 긴 옵션을 지원할 때 올바르게 작동 하지만 다른 Unices로 이식해야하는 경우에는 옵션이 아닐 수 있습니다.

최신 버전의 ksh93 ( getopts) 및 zsh ( zparseopts)는 대부분의 Unices에서 사용할 수 있으므로 긴 옵션의 구문 분석을 기본적으로 지원합니다 (기본적으로 설치되지는 않음).

또 다른 옵션은 현재 전체 스크립트를 작성 하거나 옵션을 구문 분석하고 추출 된 정보를 쉘에 공급하기 위해 perl을 호출 하여 대부분의 Unices에서 사용할 수있는 모듈 perlGetopt::Long모듈 을 사용 하는 것 perl입니다. 다음과 같은 것 :

parsed_ops=$(
  perl -MGetopt::Long -le '

    @options = (
      "foo=s", "bar", "neg!"
    );

    Getopt::Long::Configure "bundling";
    $q="'\''";
    GetOptions(@options) or exit 1;
    for (map /(\w+)/, @options) {
      eval "\$o=\$opt_$_";
      $o =~ s/$q/$q\\$q$q/g;
      print "opt_$_=$q$o$q"
    }' -- "$@"
) || exit
eval "$parsed_ops"
# and then use $opt_foo, $opt_bar...

참조 perldoc Getopt::Long는 무엇을 할 수 있는지과는 다른 옵션을 파서 어떻게 다른지.


2

이 문제에 대한 모든 논의는 구문 분석 코드를 수동으로 작성하는 옵션을 강조 표시 한 후에 만 ​​기능과 이식성을 확신 할 수 있습니다. 사용하기 쉬운 오픈 소스 코드 생성기로 생성하고 다시 생성 할 수있는 코드를 작성하지 않는 것이 좋습니다. 문제에 대한 명확한 답변을 제공하도록 설계된 Argbash를 사용하십시오 . 명령 줄 응용 프로그램 , 온라인 또는 Docker 이미지 로 사용할 수 있는 잘 문서화 된 코드 생성기 입니다.

bash 라이브러리에 대해 조언합니다. 일부 라이브러리는 사용 getopt하기가 어렵고 읽을 수없는 거대한 셸 Blob을 스크립트와 함께 번들로 묶는 것은 고통 스럽습니다.


0

getopt이를 지원하는 시스템에서 사용 하고 지원하지 않는 시스템에서는 대체를 사용할 수 있습니다.

예를 들어 pure-getopt순수 Bash로 구현되어 GNU를 대체 할 수 있습니다 getopt.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.