여러 변수가 설정되어 있는지 테스트


19

스크립트의 특정 지점 source에서 구성 파일을 사용한 후 여러 변수가 설정되고 그렇지 않은 경우 실행을 중지하여 누락 된 변수에 대해 사용자에게 알리고 싶습니다 . 나는 시도했다

for var in $one $two $three ; do
    ...

그러나 예를 들어 $two설정되어 있지 않으면 루프가 절대 실행되지 않습니다 $two. 다음으로 시도한 것은

for var in one two three ; do
    if [ -n ${!var} ] ; then
        echo "$var is set to ${!var}"
    else
        echo "$var is not set"
    fi
done

그러나 2를 설정하지 않으면 "2가 설정되지 않았습니다"대신 "2가 설정되었습니다"라는 메시지가 계속 표시됩니다.

모든 필수 변수가 설정되었는지 어떻게 확인할 수 있습니까?

업데이트 / 솔루션 : "set"과 "set, but empty"사이에 차이가 있음을 알고 있습니다. 이제 /programming//a/16753536/3456281 및이 질문에 대한 답변 덕분에 다음을 사용합니다.

if [ -n "${!var:-}" ] ; then

따라서 var설정되어 있지만 비어 있으면 여전히 유효하지 않은 것으로 간주됩니다.


1
set -u스크립트의 시작 부분에 추가 하여 설정되지 않은 변수가 사용될 때 즉시 종료 할 수도 있습니다 .
n.st

답변:


8

인용 오류.

if [ -n "${!var}" ] ; then

미래를 위해 : 설정

set -x

코드를 실행하기 전에 문제를 보여 주었을 것입니다. 코드에 코드를 추가하는 대신

bash -vx ./my/script.sh

이것은 작동하지만 따옴표로 어떤 일이 일어나고 있습니까? 내 일반적인 접근 방식이 처음부터 정확합니까?
재스퍼

그래, 예지의 : 나는 질문하기 전에 질문에 대답 ... 8)
Hauke Laging

4
@Jasper 항상 변수를 인용 해야 합니다. 매번 이것이 필요한지 생각하는 것보다 시간이 오래 걸리지 않습니다. 그러나 오류를 피합니다.
Hauke ​​Laging

반대로 인용은 확장을 막기 만합니다. 확장이 당신이 관심있는 것이라면 인용은 확실히 갈 길이 아닙니다. 예를 들어 : cs = 673,290,765; set-$ (IFS =,; echo $ cs); 에코 $ #; 출력 : 3
mikeserv

2
@mikeserv 작은 따옴표만으로 내가 암시하지 않는 확장을 막을 수 있습니다. 큰 따옴표는 단어 분리를 방지합니다. 인용을 생략 해야하는 경우가 있음을 부인하지 않았습니다. 그러나 그것은 나의 일반적인 규칙에 대한 논쟁이 아닙니다. 어떤 종류의 사람들이 어떤 것을 사용할 것 set -- $(IFS=, ; echo $cs)입니까? 왜 여기에서 물어보아야 if [ -n ${!var} ] ; then합니까? 아마 아닙니다.
Hauke ​​Laging

5

필요한 것은 테스트에서 따옴표입니다.

for var in one two three ; do
    if [ -n "${!var}" ] ; then
        echo "$var is set to ${!var}"
    else
        echo "$var is not set"
    fi
done

나를 위해 작동합니다.


4

프로그램을 중지하려면 다음을 수행하십시오.

N= 
${one?var 1 is unset} 
${two:?var 2 is unset or null}
${three:+${N:?var 3 is set and not null}}

그 트릭을 할 것입니다. 물음표 다음에 나오는 각 메시지가 인쇄되고 stderr부모 셸이 죽습니다. 글쎄요, 메시지가 아니라 하나만 – 실패한 첫 번째 메시지는 메시지를 인쇄하여 쉘이 죽게합니다. 이 테스트를 다음과 같이 사용하고 싶습니다.

( for v in "$one" "$two" "$three" ; do
    i=$((i+1)) ; : ${v:?var $i is unset or null...} 
done ) || _handle_it

나는 이것에 대해 할 말이 더 많았 습니다 .


2

추가 할 수 있습니다

set -u

설정되지 않은 변수를 사용하려고 할 때 스크립트가 시작되도록 스크립트의 시작 부분에

같은 스크립트

#!/bin/sh
set -u
echo $foo

결과

script.sh : 3 : script.sh : foo : 매개 변수가 설정되지 않았습니다

bash대신 사용 하는 경우 오류는 다음과 같습니다.

script.sh : 라인 3 : foo : 언 바운드 변수


그리고 당신의 의견으로는 런타임 검사에 어떤 의미가 있습니까?
Hauke ​​Laging

2
@HaukeLaging 나는 당신을 따르지 않습니다-OP set -u가 피하려고하는 종류의 오류를 방지하고 (다른 모든 솔루션과 달리) 특정 변수 세트로 제한되지 않습니다. 실제로 변수가 설정되지 않은 경우 예기치 않은 작업을 수행하는 대신 거의 모든 셸 스크립트가 안전하게 실패하도록하는 것이 예방책입니다. 이 기사 는 주제에 대한 편리한 참조입니다.
n.st

@ n.st 나는 동의하지 않습니다-null은 계획하려는 경우 null이 아닌 유용한 값 일 수 있습니다.
mikeserv

1
@ n.st 설정되지 않은 변수 (BTW : 설정되었지만 비어있는 변수는 동일한 오류를 유발하지만 "보호"에 반응하지 않음)에 대한 액세스를 보호하지 않기 때문에 OP에는 아무런 의미가 없습니다. 변수가 설정되지 않았거나 비어 있는지 런타임 검사를 원합니다. 귀하의 제안은 일반적인 개발 지원으로 유용 할 수 있지만 OP의 문제를 해결하지는 못합니다.
Hauke ​​Laging

set -u내가 생각하는대로 사용할 수도 있지만 적절한 매개 변수 확장만큼 유연하지 않습니다 (업데이트 된 질문 참조). 그리고 set -u한 곳에서 존재 여부를 확인하려면 모든 대상 변수에 더미 액세스해야합니다.
재스퍼

2

가장 친숙한 솔루션은 모든 요구 사항을 최대한 테스트하고 처음부터 실패하고 문제를 해결하기 위해 앞뒤로 요구하지 않고 함께보고합니다.

#!/bin/bash

required_vars=(one two three)

missing_vars=()
for i in "${required_vars[@]}"
do
    test -n "${!i:+y}" || missing_vars+=("$i")
done
if [ ${#missing_vars[@]} -ne 0 ]
then
    echo "The following variables are not set, but should be:" >&2
    printf ' %q\n' "${missing_vars[@]}" >&2
    exit 1
fi

배열 변수를 사용하여 설정되지 않은 변수를 추적하고 결과를 사용하여 사용자가 직면 한 메시지를 작성합니다.

노트:

  • 나는 인용 ${required_vars[@]}에서 for주로 습관에서 루프 - 나는 당신의 변수 이름에 대한 어떠한 쉘 메타 문자를 포함하여 조언 않을 것이다!
  • 나는 ${#missing_vars[@]}위의 조언을 무시할 정도로 충분히 변하더라도 항상 정수이므로 인용하지 않았습니다 .
  • %q인쇄 할 때 사용했습니다 . %s일반적으로 충분합니다.
  • 오류 출력은 항상 오류 스트림으로 이동 >&2하므로 다운 스트림 명령으로 파이프되지 않습니다.
  • 침묵은 금입니다-특별히 요청하지 않는 한 진행 정보 또는 디버깅 정보를 인쇄하지 마십시오. 오류가 더 분명해집니다.

1

bash4.2 변수를 -v연산자 로 설정했는지 테스트 할 수 있습니다 . 설정되지 않은 변수와 빈 문자열로 설정된 변수는 서로 다른 두 가지 조건입니다.

$ unset foo
$ [[ -v foo ]] && echo foo is set
$ [[ -z "$foo" ]] && echo foo is empty
foo is empty
$ foo=
$ [[ -v foo ]] && echo foo is set
foo is set
$ [[ -z "$foo" ]] && echo foo is empty
foo is empty

나는 "복수의"변수에 대해 묻고 있었기 때문에 간접적 인 것과 같은 것을 찾고있었습니다.
Jasper

당신은 이후, 간접 필요하지 않습니다 -v소요 이름을 때문에, 변수의 for var in one two three; [[ -v $var ]] && ...; done각 있는지 확인 것 one, two그리고 three순서로 설정됩니다.
chepner

1

의미하는 경우 not set변수를 초기화해서는 안됩니다. 을 사용 [ -n "${!var}" ]하면 설정된 빈 변수와 같이 빈 변수 two=""가 실패 합니다 . 당신은 이것을 시도 할 수 있습니다 :

one=1
three=3

for var in one two three; do
  declare -p $var > /dev/null 2>&1 \
  && printf '%s is set to %s\n' "$var" "${!var}" \
  || printf '%s is not set\n' "$var"
done

0

sourced 스크립트가 변수를 null 값으로 설정 해도되는 경우를 처리하기위한 간결한 (약간 해키이지만) 해결책은 스크립트를 소싱하기 전에 변수를 특정 값으로 초기화 한 다음 나중에 해당 값을 확인하는 것입니다. 예를 들어

one=#UNSET#
two=#UNSET#
three=#UNSET#

. set_vars_script

if [[ $one$two$three == *#UNSET#* ]] ; then
  echo "One or more essential variables are unset" >&2
  exit 1
fi

1
또 다른 좋은 해결책이지만, 좀 더 구체적인 오류 메시지를주고 싶을 때 "하나 이상의 변수가 설정되지 않았습니다"...
Jasper

0

@ mikeserv의 답변을 확장했습니다 .

이 버전은 존재 여부를 확인하고 누락 된 변수의 이름을 인쇄하며 오류 발생시 usage () 호출을 트리거하는 변수 목록을 사용합니다.

REQD_VALUES=("VARIABLE" "FOO" "BAR" "OTHER_VARIABLE")
( i=0; for var_name in ${REQD_VALUES[@]}; do
    VALUE=${!var_name} ;
    i=$((i+1)) ; : ${VALUE:?$var_name is missing}
done ) || usage

값이 없을 때의 출력 예 :

./myscript.sh: line 42: VALUE: OTHER_VARIABLE is missing

VALUE라는 변수를 원하는 출력에 더 적합한 대체 이름으로 변경할 수 있습니다.

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