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

셸/Bash 스크립트 명령줄 인수 완벽 가이드 – getopts부터 반복문까지

이 튜토리얼에서는 Bash(배시) 스크립트에 명령줄 인수를 전달하는 방법을 설명합니다. 바로 따라 해볼 수 있도록 다양한 예제도 함께 준비했습니다.

Bash/셸 스크립트는 리눅스 작업 흐름을 자동화하고 업무 속도를 크게 높여주는 강력한 도구입니다. 반복적인 작업을 스크립트로 처리하면 퇴근 시간까지 여유롭게 시간을 벌 수 있죠.

스크립트를 재사용 가능하게 만들면 활용 가치가 더욱 높아집니다. 서로 다른 데이터나 날짜마다 같은 작업을 수행하는 스크립트를 일일이 새로 작성할 필요 없이, 하나의 스크립트를 재사용하면서 명령줄을 통해 전달되는 매개변수(parameter)만 바꿔주면 됩니다. 이를 명령줄 인수(argument)라고도 부릅니다.

예를 들어, 특정 텍스트를 파일로 출력하는 스크립트가 있다고 가정해 보겠습니다. 파일 이름을 바꾸려면 스크립트를 수정해야 하고, 여러 파일에 출력하려면 스크립트 사본을 여러 개 만들어야 할 것입니다. 하지만 매개변수를 활용하면 단 하나의 스크립트로 명령줄에서 전달된 임의의 이름과 개수의 파일에 모두 출력할 수 있습니다.

이러한 매개변수, 즉 옵션(option)과 그 값(value)을 스크립트에 전달하는 방법은 목적에 따라 여러 가지가 있습니다. 지금부터 대표적인 세 가지 방법을 예제와 함께 살펴보겠습니다.

1. getopts / 플래그 방식으로 명령줄 입력 읽기

  • getopts는 셸 내장 명령으로, 명령줄 입력에서 옵션(또는 플래그)를 추출하고 해당 (또는 인수)를 스크립트 안에서 사용할 수 있게 해줍니다.
    • 옵션은 -(대시) 하나와 한 글자로 구성되며, 그 뒤에 전달할 값이 붙습니다. 예: -v value
  • 옵션 순서가 중요하지 않은 경우에 적합합니다
  • 여기 소개된 방법 중 가장 권장되는 방식입니다

getopts Bash 스크립트 예제

다음 예제 스크립트는 패스트푸드 주문을 위해 세 가지 옵션을 받습니다:

  • -o: 주문(order)
  • -s: 크기(size)
  • -d: 음료(drink)

fastFoodOrder.sh

#!/bin/bash

# while 루프로 o, s, d 옵션을 순회하며 파싱합니다
while getopts o:s:d: flag
do

    # case 문으로 각 옵션($flag 변수에 할당됨)의 의미를 매칭합니다
    # OPTARG에는 getopts가 해당 옵션에 대해 받은 값이 들어 있으며,
    # 플래그에 따라 알맞은 변수에 할당됩니다
    case "${flag}" in
        o) order=${OPTARG};;
        s) size=${OPTARG};;
        d) drink=${OPTARG};;
    esac

done

# 옵션으로 전달된 값들이 이제 각 변수에서 사용 가능합니다
echo "Order: $order";
echo "Size: $size";
echo "Drink: $drink";

참고로 스크립트 첫 줄의 #!/bin/bash는 '셔뱅(shebang)'이라 불리는 선언문으로, 이 스크립트를 Bash로 실행하겠다는 의미입니다.

실행 방법은 다음과 같습니다:

bash ./fastFoodOrder.sh -d Cola -o 'Fish Burger Meal' -s Large

스크립트 실행 결과:

Order: Fish Burger Meal
Size: Large
Drink: Cola

위 출력에서 볼 수 있듯이, 옵션을 제공한 순서는 결과에 영향을 주지 않습니다. 이것이 getopts 방식의 가장 큰 장점입니다.

같은 옵션에 여러 값 전달하기

하나의 옵션을 여러 번 사용해 여러 값을 전달할 수도 있습니다. 이 경우 값들은 스크립트 내부에서 배열 형태로 사용할 수 있습니다.

이것이 하나의 옵션에 여러 값을 전달하는 가장 좋은 방법입니다. 값에 어떤 문자든 자유롭게 사용할 수 있기 때문입니다. 따옴표로 묶거나 구분자를 사용하는 다른 방식은 이런 유연성이 떨어집니다.

fastFoodOrderExtras.sh

#!/bin/bash

# while 루프로 o, s, d, e 옵션을 순회하며 파싱합니다
while getopts o:s:d:e: flag
do

    # case 문으로 각 옵션의 의미를 매칭합니다
    case "${flag}" in
        o) order=${OPTARG};;
        s) size=${OPTARG};;
        d) drink=${OPTARG};;
        e) extras+=("${OPTARG}");; # 전달된 추가 옵션 값들을 배열 변수에 저장 또는 추가
    esac

done

# 옵션으로 전달된 값들이 이제 각 변수에서 사용 가능합니다
echo "Order: $order";
echo "Size: $size";
echo "Drink: $drink";
echo "추가 옵션 목록: '${extras[@]}'"

# 여러 개의 추가 옵션 값을 순회하며 출력합니다
for val in "${extras[@]}"; do
    echo "$val"
done

위 스크립트는 여러 개의 -e 옵션을 받아 추가 메뉴(extras)를 처리합니다:

bash ./fastFoodOrderExtras.sh -d Cola -o 'Fish Burger Meal' -s Large -e Sauce -e Salt -e Pepper

실행 결과:

Order: Fish Burger Meal
Size: Large
Drink: Cola
추가 옵션 목록: 'Sauce Salt Pepper'
Sauce
Salt
Pepper

2. 위치 매개변수(Positional Parameters) 사용하기

  • 인수의 개수와 순서가 미리 정해져 있는 경우에 사용합니다
  • 간단한 스크립트에 가장 적합합니다

예제

fastFoodOrder.sh

#!/bin/bash

echo "Order: $1";
echo "Size: $2";
echo "Drink: $3";

$1, $2, $3처럼 달러 기호와 숫자로 각 위치의 인수에 직접 접근할 수 있습니다. 실행 방법은 다음과 같습니다:

bash ./fastFoodOrder.sh 'Fish Burger Meal' Large Cola

실행 결과:

Order: Fish Burger Meal
Size: Large
Drink: Cola

단, 이 방식에서는 순서가 매우 중요합니다. 옵션 순서가 어긋나면 값들이 모두 엉키게 됩니다.

bash ./fastFoodOrder.sh 'Fish Burger Meal' Cola Large

위처럼 순서를 잘못 입력하면 값이 잘못 할당됩니다:

Order: Fish Burger Meal
Size: Cola
Drink: Large

3. 반복문으로 명령줄 매개변수 읽기

  • 옵션/인수의 개수를 미리 알 수 없는 경우에 가장 적합합니다
    • 예를 들어, 레시피에 필요한 재료 목록처럼 개수가 유동적인 입력을 받을 때 유용합니다
  • 사용자가 입력한 모든 인수를 배열로 담고 있는 내장 변수 $@를 활용합니다

예제

recipe.sh

#!/bin/bash

i=1; # 반복 횟수를 추적하는 카운터(iterator) 값입니다

for ingredient in "$@" # 전달된 모든 입력 매개변수가 담긴 배열 $@를 순회합니다
do
    echo "Ingredient number $i is $ingredient"; # 스크립트 호출 시 전달된 각 재료를 출력합니다
    i=$((i + 1)); # 몇 번 반복했는지 알 수 있도록 카운터를 1씩 증가시킵니다
done

실행 방법:

sh ./recipe.sh bread lettuce cheese hamburger

실행 결과:

Ingredient number 1 is bread
Ingredient number 2 is lettuce
Ingredient number 3 is cheese
Ingredient number 4 is hamburger

마치며 – 세 가지 방식을 정리하면 다음과 같습니다. 옵션 순서가 자유롭고 견고한 스크립트를 원한다면 getopts, 인수가 적고 순서가 고정된 간단한 스크립트라면 위치 매개변수, 개수가 정해지지 않은 목록형 입력이라면 $@와 반복문을 사용하는 것이 좋습니다. 상황에 맞는 방법을 선택해 스크립트의 재사용성을 극대화해 보세요.