getopts를 사용하여 모든 매개변수를 다른 소스 bash 스크립트에 전달

getopts를 사용하여 모든 매개변수를 다른 소스 bash 스크립트에 전달

한 스크립트에서 다른 스크립트로 모든 매개변수를 전달하려고 합니다. 그러나 다른 스크립트를 가져올 때 문제가 발생합니다. 모든 매개변수가 올바르게 전달되지 않습니다.

첫 번째.sh:

#!/usr/bin/bash


while getopts a option 
do 
    case "${option}"
    in
    a) echo 'OptionA:somevalue';; 
    esac 
done

# This way works
./second.sh "$@"

# Does not work when source command is used
#source ./second.sh "$@"

두 번째.sh:

#!/usr/bin/bash


while getopts b:c option 
do 
    case "${option}"
    in
    b) echo 'OptionB:'"${OPTARG}";; 
    c) echo 'OptionC:somevalue';;
    esac 
done

산출:

$ ./test.sh -a -b foo -c
OptionA:somevalue
./first.sh: illegal option -- b
./second.sh: illegal option -- a
OptionB:foo
OptionC:somevalue

예상 출력:

$ ./test.sh -a -b foo -c
OptionA:somevalue
OptionB:foo
OptionC:somevalue

달성하려는 목표는 무엇입니까?

second.sh매개변수를 올바르게 전달하고 , 제거하고 illegal option, 다른 쉘과 호환되도록 하려면 source 명령을 사용하십시오 .

편집 : 더 명확한 예를 들어 질문을 다시 업데이트했습니다.

답변1

while getopts일반적인 상황에서 루프가 어떻게 작동하는지 고려하십시오 . getopts명령줄 인수 자체(위치 인수)를 수정하지 않더라도 루프가 반복될 때마다 호출되며 다음에 찾을 인수 목록의 위치를 ​​알아야 합니다. 호출에서 명시적으로 전달되지 않는 "숨겨진" 상태를 유지하여 이를 수행해야 합니다.

이것은배쉬 참조 매뉴얼:

호출할 때마다 getopts다음 옵션을 쉘 변수에 넣습니다.이름, 초기화이름존재하지 않는 경우 변수로 처리될 다음 매개변수의 인덱스입니다 OPTIND. OPTIND쉘 또는 쉘 스크립트가 호출될 때마다 1로 초기화됩니다. 옵션에 인수가 필요한 경우 getopts는 인수를 변수에 넣습니다 OPTARG.쉘은 OPTIND자동으로 재설정되지 않습니다. getopts새로운 매개변수 세트를 사용하려면 동일한 쉘 호출 내에서 호출 간에 수동으로 재설정해야 합니다.

스크립트를 얻으면 OPTIND.

설명서에 나와 있듯이 OPTIND=1getopts주기를 시작하기 전에 설정하기만 하면 됩니다. (설정을 해제하려고 시도하지 마십시오. 이로 인해 일부 쉘에 문제가 발생할 수 있습니다.)


예를 들어:

set -- -a foo
while getopts a:b: option; do
    echo "$option: $OPTARG"
done
set -- -b first -b second
# OPTIND=1
while getopts a:b: option; do
    echo "$option: $OPTARG"
done

인쇄

a: foo
b: second

두 번째 루프는 첫 번째 루프가 끝난 곳에서 계속되기 때문에 -b first.

OPTIND=1중간 할당의 주석을 해제 하면 예상되는 출력을 얻을 수 있습니다.

a: foo
b: first
b: second

매개변수를 별도로 저장하는 경우 단일 문자열이 구성되는 반면 $@, args+="-a ${OPTARG} "명령줄 매개변수 세트는 실제로 다양한 문자열의 목록/배열입니다. 매개변수 자체에 공백이 포함된 경우 차이점이 가장 두드러집니다. 두 개의 인수 집합( -a, foo bar)과 ( -a foo, bar)이 연결되어 있으며 -a foo bar후자의 문자열은 구별할 수 없습니다.

대신 배열을 사용하여 매개변수를 고유한 문자열로 저장하세요.

while getopts a:b:d option 
do 
    case "${option}"
    in
    a) args+=(-a "$OPTARG");; 
    b) args+=(-b "$OPTARG");; 
    d) echo 'Option:D';; 
    esac 
done
# ...
./args.sh "${args[@]}"

(바라보다 변수에 저장된 명령을 어떻게 실행할 수 있나요?더 많은 예를 보려면 등)


알아채다,표준 .(점) 명령소스 스크립트는 매개변수를 사용하지 않지만 소스 스크립트는 $@기본 스크립트와 동일합니다. (소스 스크립트에서 변경된 내용은 $@기본 스크립트에 표시됩니다.)

Bash ./는 source새로운 인수 세트 전달을 지원 하지만 source filename인수 세트 없이 호출하면 소스 스크립트는아니요빈 목록을 가져오지만 기본 스크립트에 대한 매개변수가 포함되어 있습니다.

그렇다면 다음과 같이 하세요.

source ./args.sh "${args[@]}"

비어 있지 않은지 확인하는 것이 좋습니다 args. 아니면 다른 스크립트를 가져오기 전에 기본 스크립트의 매개변수를 재설정하세요. 물론 이렇게 하면 원래 매개변수 세트가 파괴되지만 필요한 경우 먼저 다른 배열에 저장할 수 있습니다.

orig_args=( "$@" )   # if needed 
set -- "${args[@]}"
source ./args.sh

관련 정보