Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

Bash 셸 스크립트에 옵션 추가하는 방법

터미널 명령어에는 대개 옵션(option) 또는 스위치(switch)가 포함되어 있으며, 이를 활용하면 명령어의 동작 방식을 원하는 대로 조정할 수 있습니다. 옵션은 POSIX 명령줄 인터페이스 사양에도 포함되어 있고, 초기 UNIX 애플리케이션부터 이어져 온 오랜 관습이기도 합니다. 따라서 자신만의 명령어를 만드는 Bash 스크립트에 옵션을 구현하는 방법을 알아두면 큰 도움이 됩니다.

대부분의 프로그래밍 언어와 마찬가지로 Bash에서도 옵션을 파싱하는 방법은 여러 가지입니다. 지금까지도 제가 가장 선호하는 방식은 Patrick Volkerding의 Slackware 빌드 스크립트에서 배운 것입니다. Linux를 처음 접했을 때 OS에 함께 배포되던 일반 텍스트 파일에 모험 삼아 뛰어들었고, 그 과정에서 셸 스크립팅을 처음 익히게 되었는데, 그 시작점이 바로 그 스크립트였습니다.

Bash에서 옵션 파싱하기

Bash에서 옵션을 파싱하는 전략은 다음과 같습니다. 셸 스크립트에 전달된 모든 인수를 순회하면서 각 인수가 옵션인지 판별하고, 옵션이라면 처리한 뒤 다음 인수로 이동(shift)합니다. 더 이상 남은 옵션이 없을 때까지 이 과정을 반복합니다.

먼저 간단한 불리언(Boolean) 옵션(스위치 또는 플래그라고도 함)부터 시작해 보겠습니다.

#!/bin/bash

while [ True ]; do
if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
    ALPHA=1
    shift 1
else
    break
fi
done

echo $ALPHA

이 코드에서는 while 루프를 만들어 처리할 인수가 더 이상 없을 때까지 반복하도록 했습니다. if 문은 첫 번째 위치($1)에 있는 인수가 --alpha 또는 -a와 일치하는지 검사합니다. 여기서 사용한 옵션 이름은 임의로 정한 것일 뿐 특별한 의미는 없으며, 실제 스크립트에서는 상세 출력을 활성화하기 위해 --verbose-v를 사용하는 식으로 응용할 수 있습니다.

shift 키워드는 모든 인수를 1칸씩 앞으로 이동시킵니다. 즉, 2번째 위치($2)의 인수가 1번째 위치($1)로 이동합니다. else 문은 더 이상 처리할 인수가 없을 때 실행되며, 이 시점에 while 루프를 빠져나갑니다.

스크립트 마지막에는 $ALPHA 변수의 값이 터미널에 출력됩니다.

스크립트를 테스트해 보겠습니다.

$ bash ./test.sh --alpha
1
$ bash ./test.sh

$ bash ./test.sh -a
1

옵션이 올바르게 감지되는 것을 확인할 수 있습니다.

옵션이 아닌 일반 인수 감지하기

그런데 한 가지 문제가 있습니다. 옵션이 아닌 추가 인수들이 그대로 무시된다는 점입니다.

$ bash ./test.sh --alpha foo
1
$

옵션이 아닌 인수까지 처리하려면 나머지 인수들을 Bash 배열에 담으면 됩니다.

#!/bin/bash

while [ True ]; do
if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
    ALPHA=1
    shift 1
else
    break
fi
done

echo $ALPHA

ARG=( "${@}" )
for i in ${ARG[@]}; do
    echo $i
done

새 버전의 스크립트를 테스트해 보겠습니다.

$ bash ./test.sh --alpha foo
1
foo
$ bash ./test.sh foo

foo
$ bash ./test.sh --alpha foo bar
1
foo
bar

인수를 필요로 하는 옵션

일부 옵션은 자체적으로 인수를 하나 더 요구합니다. 예를 들어 사용자가 색상이나 이미지 해상도 같은 속성을 직접 지정하게 하거나, 애플리케이션이 사용자 지정 설정 파일을 참조하도록 만들 수 있습니다.

Bash에서 이를 구현하려면 불리언 스위치와 마찬가지로 shift 키워드를 사용하되, 인수를 1칸이 아닌 2칸씩 이동시키면 됩니다.

#!/bin/bash

while [ True ]; do
if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
    ALPHA=1
    shift 1
elif [ "$1" = "--config" -o "$1" = "-c" ]; then
    CONFIG=$2
    shift 2
else
    break
fi
done

echo $ALPHA
echo $CONFIG

ARG=( "${@}" )

for i in ${ARG[@]}; do
    echo $i
done

이 코드에는 elif 절을 추가하여 각 인수를 --config-c와 비교합니다. 일치하는 경우 CONFIG라는 변수에 두 번째 인수의 값이 할당됩니다. 즉, --config 옵션은 인수를 하나 요구하는 구조입니다. 이후 모든 인수를 2칸씩 이동시키는데, 하나는 --config 또는 -c 자체를 넘기기 위함이고, 다른 하나는 해당 옵션의 인수를 넘기기 위함입니다. 그다음에는 평소처럼 일치하는 인수가 더 이상 없을 때까지 루프가 반복됩니다.

새 버전의 스크립트를 테스트해 보겠습니다.

$ bash ./test.sh --config my.conf foo bar
my.conf
foo
bar
$ bash ./test.sh -a --config my.conf baz
1
my.conf
baz

쉽게 구현하는 옵션 파싱

Bash에서 옵션을 파싱하는 방법은 이 외에도 여러 가지가 있습니다. case 문을 사용하거나 getopt 명령어를 활용할 수도 있습니다. 어떤 방법을 선택하든, 사용자에게 옵션을 제공하는 것은 모든 애플리케이션에서 중요한 기능이며, Bash는 이를 손쉽게 구현할 수 있게 도와줍니다.