설정되지 않은 변수를 사용하면 어떤 해가 있습니까?

설정되지 않은 변수를 사용하면 어떤 해가 있습니까?

다음 코드가 있다고 가정해 보겠습니다.

# Check if the color prompt is enabled and supported on this system
if [ -n "$force_color_prompt" ] && [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
    GREEN="\033[1;32m"
    DIM="\033[2m"
    RESET="\033[00m"
fi

echo -e "Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"

색상 지원이 활성화되면 멋진 색상의 선이 표시됩니다. 색상 지원이 활성화되지 않은 경우 ${GREEN}유사한 값이 설정되지 않으며 텍스트는 일반적인 흰색과 검정색 배경으로 인쇄됩니다.

이 코드는 설정되지 않은 변수가 단순히 빈 문자열로 평가된다는 사실에 의존합니다(내 테스트에서는 그랬습니다). 이로 인해 일부 시스템에서 오류나 문제가 발생합니까, 아니면 존재하지 않는 모든 변수가 발생합니까?언제나빈 문자열로 평가됩니까? 이 메커니즘에 의존하면 안 되는 이유가 있나요?

답변1

$FOO또는 (동등)로 확장되면 존재하지 않는 변수는 항상 빈 문자열로 평가되며 ${FOO}다음과 같은 특별한 경우를 제외하고 이에 의존해도 아무런 해가 없습니다.

set -u이 변수를 사용하기 전에 현재 셸에서 누군가 호출된 경우 해당 설정이 활성화된 것입니다.

              -u 인수 실행 시 설정되지 않은 변수를 오류로 처리합니다.
                      더 확장하세요. 설정하지 않고 확장하려는 경우
                      변수가 없으면 쉘은 오류 메시지를 인쇄합니다.
                      대화형, 0이 아닌 상태로 종료됩니다.

즉, 다른 사람이 제어하는 ​​스크립트에 소스로 제공되도록 설계된 함수를 작성하는 경우 설정되지 않은 변수를 사용하는 것에 대해 편집증이 필요할 수 있습니다. 그렇지 않으면 set -u함수를 호출하기 전에 사용하는 경우 스크립트가 오류와 함께 종료됩니다. 설정되지 않은 변수를 처음 확장하려고 시도했을 때 메시지가 표시됩니다.

자신만의 스크립트를 작성하는 경우 빈 문자열로 확장되는 설정되지 않은 변수에 의존해도 아무런 해가 없습니다.

편집하다- 또한 생각해 보세요. 터미널에서 terminfo 색상 기능을 사용할 수 있는지 여부에 따라 모든 것을 조건부로 만들고 있으므로 vt100 값을 하드코딩하는 대신 실제로 terminfo를 사용하여 시퀀스를 생성하는 것은 어떨까요? 그것은 다음과 같습니다:

if [ -n "$force_color_prompt" ] && type tput &>/dev/null; then
    GREEN="$(tput setaf 2)$(tput bold)"
    DIM="$(tput dim)"
    RESET="$(tput sgr0)"
fi

이는 다른 터미널에서 어느 정도 이식성을 제공할 수 있습니다(물론 표시된 코드를 사용하지 않는 터미널의 수는 적고 줄어들고 있습니다). 또한 terminfo가 얼마나 정확하게 정의되었는지에 따라 일부 플랫폼에서는 일부 기능이 존재하지 않을 수 있으므로 일부 이식성을 잃을 수도 있습니다. YMMV.

답변2

POSIX 호환 쉘 스크립팅 언어의 가장 독특한 기능 중 하나는매개변수 확장. 일반적으로 변수 값과 연관되지 않는 작업을 수행하기 위해 다양한 방법으로 사용될 수 있습니다. 셸에서 변수는 단순한 값이 아니라 작동 가능한 항목일 수도 있습니다. 자체적으로 테스트할 수 있는 가능성이 있습니다. 이는 분명합니다. 쉘 옵션을 설정할 필요가 없습니다.

예를 들어 코드는 다음과 같습니다.

N= ERR='error encountered - exiting' 
: ${force_color_prompt?"$ERR"}
/usr/bin/tput setaf >/dev/null 2>&1 || ${N:?"$ERR"}
: "${GREEN:=\033[1;32m}" "${DIM:=\033[2m}" "${RESET:=\033[00m}"
printf %b\\n \
    "Oh, ${GREEN}green${RESET} world, ${DIM}don't desert me now...${RESET}"

$N변수는 명시적으로 빈 문자열로 설정되므로 ${N:?}매개변수 확장으로 평가될 때 상위 쉘이 자동으로 종료되고 후속 명령문 ?도 확장되며 그 결과는 위에 인쇄됩니다 stderr. 동일하게 적용됩니다 $force_color_prompt. 설정되지 않은 경우 스크립트는 오류와 함께 종료되고 자동으로 - $ERR로 출력됩니다 stderr.

및가 현재 설정되어 있지 않거나 빈 문자열로 설정된 경우 $GREEN $RESET정의한 값으로 설정됩니다. 이를 통해 해당 값을 환경 변수로 스크립트에 전달할 수 있습니다. 예를 들어 위의 코드 조각이 라는 스크립트에 있으면 다음과 같이 호출합니다.$DIM''greenworld.sh

GREEN="$(tput setaf 2)$(tput bold)" greenworld.sh

그러면 $GREEN스크립트 내용이 재설정되지 않고 대신 내가 설정한 명시적 값이 상속됩니다. 이는 쉘 스크립트를 유연하게 만듭니다.

이런 식으로 사용하는 것은 godlygeek이 제안한 tput제안 중 하나입니다 .

셸에서는 설정되지 않은 변수가 설정 변수만큼 유용할 때도 있습니다. 다음은 다른 예입니다.

set -- * 
while ${1+:} false ; do
    #do stuff until all positionals are shifted away
shift ; done

이 예에서는 첫 번째 인수가 정의될 ​​때마다 셸의 내장 :null로 확장되어 다음 false호출이 작동하지 않게 됩니다. 그러나 위치 인수가 모두 shift제거 되면 ${1}이런 방식으로 확장되지 않고 false호출되며 while루프가 종료됩니다. 이에 대해 셀 수 없이 많은 변형을 만들 수 있습니다.

답변3

일반적인 사용에서, 즉 단순히 변수를 확장하면 설정되지 않은 변수는 모든 Bourne/POSIX 스타일 쉘에서 빈 것으로 처리됩니다. 예외는 set -o unsetaka가 set -u적용되는 경우입니다. 이 경우 설정되지 않은 변수의 값에 액세스하려고 하면 셸에서 오류가 발생합니다(참조:신 괴짜의 대답).

변수가 설정되지 않았거나 비어 있는지 테스트하는 방법에는 여러 가지가 있습니다. 예를 들어 변수가 설정되어 있으면(비어 있어도) ${foo-bar}설정되지 않은 경우 해당 구문이 값으로 확장됩니다. 추가 콜론)은 빈 변수를 설정되지 않은 것으로 처리합니다. 다른 유사한 확장 구조인 는 유사하게 동작합니다. 다른 차이점 중 하나는 및(내보낸 경우)의 출력에 빈 변수가 나타납니다. 허용하는 경우에만 이러한 차이점이 발생합니다.foobarfoo
${foo:-bar}${foo+bar}${foo?bar}${foo=bar}setexport

그러나 다른 이유가 있습니다항상 변수 초기화:변수가 실제로 설정되지 않았는지 어떻게 알 수 있나요? 호출자는 자신의 목적에 맞게 유사한 변수를 정의할 수 있습니다. 호출자가 동일한 스크립트의 다른 부분인 경우 변수를 로컬 변수로 선언하지 않는 한(ksh/bash/zsh에서만 가능) 함수에서의 사용법이 호출자의 사용법을 재정의하므로 변수 이름 충돌이 발생합니다. 어쨌든 문제다. 그러나 다른 사람이 귀하와 동일한 변수 이름을 선택했기 때문에 해당 변수가 환경에 존재할 수도 있습니다. 쉘 변수에는 소문자 이름을 사용하고 환경 변수에는 대문자 이름을 사용하는 관례가 있지만 모든 충돌이 해결되지는 않으며 보편적으로 따르지 않습니다.

$ 내보내기 DIM=1 SUM=42
$ 쿵
오 녹색 세상이여, 이제 나를 버리지 마세요…

관련 정보