대체 $ {! var_name + x}은 무슨 뜻입니까?

변수가 설정되어 있는지 확인하는 기능이있는 스크립트를 찾았지만 잘 이해하지 못했습니다.

check_if_variable_is_set() {
    var_name=$1
    if [ -z "${!var_name+x}" ]; then
        false
    else
        true
    fi
}

이 대체로 정확히 어떤 일이 발생합니까?



답변

에서 bash${!var}변수 간접이다. 이름이로 유지되는 변수의 값으로 확장됩니다 $var.

변수 확장 ${var+value}은 값이 비어 있는지 여부에 관계없이 변수 가 설정 되면 확장되는 POSIX 확장 입니다 .valuevar

이것들을 조합하면 이름이 유지되는 변수 가 설정 되면 ${!var+x}확장됩니다 .x$var

예:

$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"

(출력으로 빈 줄)


문제의 기능이 단축 될 수 있습니다

check_if_variable_is_set () { [ -n "${!1+x}" ]; }

또는:

check_if_variable_is_set () { [ -v "$1" ]; }

또는:

check_if_variable_is_set()[[ -v $1 ]]

명명 된 변수가 설정되면 true가되고 그렇지 않으면 false가되는 변수 이름에 -v대한 bash테스트 는 어디에 있습니까 ?


POSIX는 다음과 같이 작성할 수 있습니다.

check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }

해당 기능에 대한 인수가 공격자에 의해 제어 될 수있는 경우 모든 명령 주입 취약점이 될 수 있습니다. 로 예를 들어보십시오 check_if_variable_is_set 'a[$(id>&2)]'.

이를 막기 위해 먼저 인수가 유효한 변수 이름인지 확인해야합니다. 변수의 경우 :

check_if_variable_is_set() {
  case $1 in
    ("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
    (*)  eval '[ -n "${'"$1"'+x}" ]'
  esac
}

( 로케일에서[[:alpha:]] 알파벳 문자 확인 하는 반면, 일부 쉘은 변수에 휴대용 문자 세트의 알파벳 문자 만 허용합니다)