다음 코드가 있다고 가정해 보겠습니다.
# 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 unset
aka가 set -u
적용되는 경우입니다. 이 경우 설정되지 않은 변수의 값에 액세스하려고 하면 셸에서 오류가 발생합니다(참조:신 괴짜의 대답).
변수가 설정되지 않았거나 비어 있는지 테스트하는 방법에는 여러 가지가 있습니다. 예를 들어 변수가 설정되어 있으면(비어 있어도) ${foo-bar}
설정되지 않은 경우 해당 구문이 값으로 확장됩니다. 추가 콜론)은 빈 변수를 설정되지 않은 것으로 처리합니다. 다른 유사한 확장 구조인 는 유사하게 동작합니다. 다른 차이점 중 하나는 및(내보낸 경우)의 출력에 빈 변수가 나타납니다. 허용하는 경우에만 이러한 차이점이 발생합니다.foo
bar
foo
${foo:-bar}
${foo+bar}
${foo?bar}
${foo=bar}
set
export
그러나 다른 이유가 있습니다항상 변수 초기화:변수가 실제로 설정되지 않았는지 어떻게 알 수 있나요? 호출자는 자신의 목적에 맞게 유사한 변수를 정의할 수 있습니다. 호출자가 동일한 스크립트의 다른 부분인 경우 변수를 로컬 변수로 선언하지 않는 한(ksh/bash/zsh에서만 가능) 함수에서의 사용법이 호출자의 사용법을 재정의하므로 변수 이름 충돌이 발생합니다. 어쨌든 문제다. 그러나 다른 사람이 귀하와 동일한 변수 이름을 선택했기 때문에 해당 변수가 환경에 존재할 수도 있습니다. 쉘 변수에는 소문자 이름을 사용하고 환경 변수에는 대문자 이름을 사용하는 관례가 있지만 모든 충돌이 해결되지는 않으며 보편적으로 따르지 않습니다.
$ 내보내기 DIM=1 SUM=42 $ 쿵 오 녹색 세상이여, 이제 나를 버리지 마세요…