NAME

getopt, getopt_long, getopt_long_only, optarg, optind, opterr, optopt - 명령행 옵션 파싱

SYNOPSIS

#include <unistd.h>

int getopt(int argc, char *const argv[],
           const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;

#include <getopt.h>

int getopt_long(int argc, char *const argv[],
           const char *optstring,
           const struct option *longopts, int *longindex);

int getopt_long_only(int argc, char *const argv[],
           const char *optstring,
           const struct option *longopts, int *longindex);

glibc 기능 확인 매크로 요건 (feature_test_macros(7) 참고):

getopt():
_POSIX_C_SOURCE >= 2 || _XOPEN_SOURCE
getopt_long(), getopt_long_only():
_GNU_SOURCE

DESCRIPTION

getopt() 함수는 명령행 인자들을 파싱 한다. 인자 argcargv는 프로그램 호출 시 main() 함수로 전달된 인자 개수 및 배열이다. argv의 항목 중 '-'로 시작하는 (그러면서 "-"이나 "--"는 아닌) 게 옵션 항목이다. 그 항목의 (처음 '-'를 제외한) 문자들이 옵션 문자이다. getopt()를 반복해서 호출하면 옵션 항목 각각의 옵션 문자 각각을 차례로 반환한다.

변수 optindargv에서 다음으로 처리할 항목의 인덱스이다. 시스템에서 이 값을 1로 초기화 한다. 호출자가 이 값을 1로 재설정해서 동일한 argv를 다시 훑거나 새로운 인자 벡터를 훑을 수 있다.

getopt()에서 옵션 문자를 또 찾으면 그 문자를 반환하고, 외부 변수 optind와 정적 변수 nextchar를 갱신해서 다음 getopt() 호출에서 그 다음 옵션 문자 내지 argv 항목을 계속 훑을 수 있도록 한다.

옵션 문자가 더는 없으면 getopt()가 -1을 반환한다. 그때 optind는 옵션이 아닌 첫 번째 argv 항목의 argv 내 인덱스이다.

optstring은 유효한 옵션 문자들을 담은 문자열이다. 그 문자 뒤에 콜론이 있으면 옵션에 인자가 있어야 하며 getopt()에서는 같은 argv 항목 내의 다음 텍스트나 다음 argv 항목의 텍스트에 대한 포인터를 optarg에 집어넣는다. 콜론이 두 개면 그 옵션이 선택적 인자를 받는다는 뜻이다. 현재 argv 항목 내에 텍스트가 있으면 (즉 동일 단어에 옵션 이름과 함께 있으면, "-oarg"처럼) optarg로 반환되고 아니면 optarg가 0으로 설정된다. 이 방식은 GNU 확장이다. 그리고 optstringW가 있고 세미콜론이 따라오면 -W foo를 긴 옵션 --foo처럼 다룬다. (-W 옵션은 POSIX.2에서 구현 확장용으로 예약돼 있다.) 이 동작 방식은 GNU 확장이며 glibc 2 전의 라이브러리에서는 사용 불가능하다.

기본적으로 getopt()에서는 argv의 내용물을 서로 바꿔서 최종적으로 옵션 아닌 것들이 뒤로 가게 한다. 그와 다른 동작 방식도 두 가지 구현돼 있다. optstring의 첫 문자가 '+'이거나 환경 변수 POSIXLY_CORRECT가 설정돼 있으면 옵션 아닌 인자를 만나자마자 처리를 멈춘다. 또 optstring의 첫 문자가 '-'이면 옵션 아닌 argv 항목 각각을 문자 코드가 1인 옵션의 인자인 것처럼 처리한다. (옵션과 다른 argv 항목들을 아무 순서로나 받을 수 있고 그 둘에서의 순서에 관심 있는 프로그램에서 이 방식을 쓴다.) 훑는 방식이 뭐든 간에 특수 인자 "--"는 옵션 탐색을 강제로 끝낸다.

옵션 목록을 처리하는 동안 getopt()는 두 가지 오류를 탐지할 수 있다. (1) optstring에 지정하지 않은 옵션 문자가 있는 경우와 (2) 옵션 인자가 빠져 있는 경우(즉 명령행 마지막 옵션에 필수 인자가 없는 경우)이다. 그런 오류들을 다음과 같이 처리하고 보고한다.

getopt_long()getopt_long_only()

getopt_long() 함수는 getopt()처럼 동작하되 대시 두 개로 시작하는 긴 옵션들도 받는다. (프로그램에서 긴 옵션만 받으려는 경우에는 optstring을 NULL아 아니라 빈 문자열("")로 지정해야 한다.) 짧게 줄인 옵션 문자가 유일하거나 이미 정의된 어떤 옵션과 일치하는 경우에는 긴 옵션 이름을 축약할 수도 있다. 긴 옵션에서는 --arg=param이나 --arg param 형태로 매개변수를 받을 수 있다.

longopts<getopt.h>에 다음처럼 선언된 struct option의 배열 첫 항목을 가리키는 포인터이다.

struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};

각 필드의 의미는 다음과 같다.

name
긴 옵션의 이름이다.
has_arg
no_argument(0)이면 옵션에 인자를 받지 않고, required_argument(1)이면 옵션에 인자가 필수이고, optional_argument(2)이면 옵션에서 선택적 인자를 받는다.
flag
긴 옵션에 대한 결과를 어떻게 반환하는지 지정한다. flag가 NULL이면 getopt_long()val을 반환한다. (예를 들어 호출 프로그램에서는 val을 대응하는 짧은 옵션 문자로 설정할 수 있다.) 아니면 getopt_long()이 0을 반환하며, 옵션을 찾았으면 flag가 가리키는 변수를 val로 설정하고 찾지 못했으면 그대로 둔다.
val
반환되는 값, 또는 flag가 가리키는 변수에 넣을 값.

배열 마지막 항목이 0으로 채워져 있어야 한다.

longindex가 NULL이 아니면 가리키는 변수를 longopts에서의 긴 옵션 인덱스로 설정한다.

getopt_long_only()getopt_long()과 비슷하되 "--"뿐 아니라 '-'로도 긴 옵션을 나타낼 수 있다. '-'로 ("--" 아님) 시작하는 옵션과 일치하는 긴 옵션이 없고 짧은 옵션은 있는 경우에는 짧은 옵션으로 파싱 한다.

RETURN VALUE

옵션을 성공적으로 찾은 경우 getopt()가 옵션 문자를 반환한다. 명령행 옵션들을 모두 파싱 했으면 getopt()가 -1을 반환한다. optstring에 없는 옵션 문자를 만났으면 getopt()가 '?'을 반환한다. 인자가 빠져 있는 옵션을 만났으면 optstring의 첫 문자에 따라 반환 값이 정해진다. 즉 첫 문자가 ':'이면 ':'을 반환하고 아니면 '?'를 반환한다.

getopt_long()getopt_long_only()도 짧은 옵션을 인식했을 때는 옵션 문자를 반환한다. 긴 옵션인 경우에는 flag가 NULL이면 val을 반환하고 아니면 0을 반환한다. 오류 및 -1 반환은 getopt()에서와 같으며, 추가로 여러 가지로 해석할 수 있는 경우나 불필요한 매개변수가 있는 경우에 '?'를 반환한다.

ENVIRONMENT

POSIXLY_CORRECT
설정된 경우 옵션 아닌 인자를 만나자마자 옵션 처리를 멈춘다.
_<PID>_GNU_nonoption_argv_flags_
bash(1) 2.0에서 이 변수를 사용했는데 어떤 인자가 와일드카드 확장의 결과이므로 옵션으로 다뤄선 안 된다는 걸 glibc에게 알려 주는 용도였다. bash(1) 버전 2.01에서 이 동작이 제거되었지만 glibc에는 지원이 남아 있다.

ATTRIBUTES

이 절에서 사용하는 용어들에 대한 설명은 attributes(7)를 보라.

인터페이스 속성
getopt(), getopt_long(),
getopt_long_only()
스레드 안전성 MT-Unsafe race:getopt env

CONFORMING TO

getopt():

환경 변수 POSIXLY_CORRECT가 설정돼 있다면 POSIX.1-2001, POSIX.1-2008, POSIX.2. 아니라면 이 함수들에서 argv의 항목들을 교환하므로 사실 const가 아니다. 그렇지만 다른 시스템과의 호환성을 위해 원형에 const를 쓴다.

optstring에 '+' 및 '-'를 쓰는 것은 GNU 확장이다.

일부 구식 구현들에서는 getopt()<stdin.h>에 선언돼 있었다. SUSv1에서는 선언이 <unistd.h><stdio.h> 어느 쪽에서 나오든 허용했다. POSIX.1-1996에서 이 용도에 <stdio.h>를 쓰는 것을 LEGACY로 표시했다. POSIX.1-2001에서는 <stdio.h>에 선언이 나와야 한다고 요구하지 않는다.

getopt_long()getopt_long_only():
이 함수들은 GNU 확장이다.

NOTES

여러 인자 벡터를 훑거나 같은 벡터를 여러 번 다시 훑는 프로그램에서 optstring 선두의 '+'와 '-' 같은 GNU 확장을 쓰고 싶거나 탐색 사이에 POSIXLY_CORRECT의 값을 바꾸고 싶은 경우에는 optind를 (전통적 값인 1 대신) 0으로 재설정해서 getopt()를 재초기화 해야 한다. (0으로 재설정하면 내부 초기화 루틴이 호출돼서 POSIXLY_CORRECT를 재확인하고 optstring의 GNU 확장을 확인한다.)

EXAMPLES

getopt()

다음의 간단한 예시 프로그램에서는 getopt()를 사용해 두 가지 프로그램 옵션을 처리한다. 연계 값이 없는 -n 옵션, 그리고 연계된 값이 필요한 -t val 옵션이다.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int
main(int argc, char *argv[])
{
    int flags, opt;
    int nsecs, tfnd;

    nsecs = 0;
    tfnd = 0;
    flags = 0;
    while ((opt = getopt(argc, argv, "nt:")) != -1) {
        switch (opt) {
        case 'n':
            flags = 1;
            break;
        case 't':
            nsecs = atoi(optarg);
            tfnd = 1;
            break;
        default: /* '?' */
            fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    printf("flags=%d; tfnd=%d; nsecs=%d; optind=%d\n",
            flags, tfnd, nsecs, optind);

    if (optind >= argc) {
        fprintf(stderr, "Expected argument after options\n");
        exit(EXIT_FAILURE);
    }

    printf("name argument = %s\n", argv[optind]);

    /* 나머지 코드 생략 */

    exit(EXIT_SUCCESS);
}

getopt_long()

다음 예시 프로그램에서는 getopt_long()의 여러 기능을 사용하는 걸 보여 준다.

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit  */
#include <getopt.h>

int main(int argc, char **argv) {
    int c;
    int digit_optind = 0;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"add",     required_argument, 0,  0 },
            {"append",  no_argument,       0,  0 },
            {"delete",  required_argument, 0,  0 },
            {"verbose", no_argument,       0,  0 },
            {"create",  required_argument, 0, 'c'},
            {"file",    required_argument, 0,  0 },
            {0,         0,                 0,  0 }
        };

        c = getopt_long(argc, argv, "abc:d:012",
                 long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 0:
            printf("option %s", long_options[option_index].name);
            if (optarg)
                printf(" with arg %s", optarg);
            printf("\n");
            break;

        case '0':
        case '1':
        case '2':
            if (digit_optind != 0 && digit_optind != this_option_optind)
              printf("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf("option %c\n", c);
            break;

        case 'a':
            printf("option a\n");
            break;

        case 'b':
            printf("option b\n");
            break;

        case 'c':
            printf("option c with value '%s'\n", optarg);
            break;

        case 'd':
            printf("option d with value '%s'\n", optarg);
            break;

        case '?':
            break;

        default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }

    exit(EXIT_SUCCESS);
}

SEE ALSO

getopt(1), getsubopt(3)


2021-03-22