$ {! FOO} 및 zsh


13

${!FOO} 이중 치환을 수행 bash 즉, FOO의 (문자열) 값을 가져와 변수 이름으로 사용합니다.
zsh이 기능을 지원하지 않습니다.

이 작업을 동일하게 만드는 방법이 있습니까? bashzsh?

배경:

다음과 같은 환경 변수 목록이 있습니다.

PATH MAIL EDITOR

먼저 변수 이름을 인쇄 한 후 값을 인쇄하려고합니다.

이것은 작동 bash하지만 작동 하지 않습니다 zsh.

for VAR in LIST
do
        echo $VAR
        echo ${!VAR}
done

와 함께 "오래된 방법"이 가능해야 eval하지만 작동시키지 못했습니다.

for VAR in LIST
do
        echo $VAR
        echo `eval \$$VAR`
done

나는 왜 내가 필요 ${${VAR}}하거나 ${${${VAR}}}필요하다면 임의의 깊은 대체를 할 수 없는지 결코 이해하지 못할 것이므로 그에 대한 설명도 좋을 것입니다.


1
하! zsh에 더 많은 기능이 있다고 생각했습니다.
Ярослав Рахматуллин

4
자랑 할 필요가 없으며 bash실제로 동일한 기능 (및 훨씬 더)이 있으며 다른 패턴 만 사용합니다 ${(p)FOO}.
Profpatsch

2
@ ЯрославРахматуллин, zsh의 (e)매개 변수 확장 플래그는 zsh-2.6-beta17 (1996 년 5 월), (P)3.1.5-pws-7 (1999)의 플래그로 추가되었습니다 . bash ${!var}는 2.0 버전입니다 (1996 년 12 월).
Stéphane Chazelas

답변:


18

bash와 zsh는 간접 확장을 수행하는 방법이 있지만 다른 구문을 사용합니다.

eval;를 사용하여 간접 확장을 수행하기에 충분히 쉽습니다 . 이것은 모든 POSIX 및 대부분의 Bourne 쉘에서 작동합니다. 값에 쉘에서 특별한 의미가있는 문자가 포함 된 경우 올바르게 인용하십시오.

eval "value=\"\${$VAR}\""
echo "$VAR"
echo "$value"

${${VAR}}쉘이 구현하는 기능이 아니기 때문에 작동하지 않습니다. 중괄호 안의 내용은 포함되지 않은 구문 규칙을 따라야합니다 ${VAR}. (zsh에서이 구문은 지원되지만 구문이 다릅니다. 중첩 된 대체는 동일한 값에서 연속 변환을 수행합니다. 이는 값에서 ID 변환을 두 번 수행하므로 ${${VAR}}동등 $VAR합니다.)


19

Profpatsch의 원래 질문 아래 주석은 ${(p)FOO}간접 변수 참조의 내용을 출력하는 예제 를 제공합니다 . 플래그가 잘못되었거나 오타 인 경우 소문자 p가 아닌 대문자 P 여야합니다. 사용하십시오 : ${(P)FOO}.

다음은 원하는 출력을 생성해야합니다.

#! /bin/zsh
LIST=(PATH MAIL EDITOR)
for VAR in ${LIST}
do
    print "${VAR}:  ${(P)VAR}"
done

로부터 zshexpn man 페이지; 섹션- 파라미터 확장 플래그 :

  This forces the value of the parameter name to be interpreted as a further
  parameter name,  whose  value  will  be used where appropriate.  Note that
  flags set with one of the typeset family of commands (in particular case
  transformations) are not applied to the value of name used in this fashion.

  If used with a nested parameter or command substitution, the result of that
  will be taken as a parameter  name  in the  same  way.   For  example,  if
  you  have  `foo=bar'  and `bar=baz', the strings ${(P)foo}, ${(P)${foo}}, and
  ${(P)$(echo bar)} will be expanded to `baz'

한 번에 나는 ${${${VAR}}}당신이 예상 한 결과를 얻지 못하는 이유를 읽었 지만 지금은 그것을 찾을 수 없습니다. 다음과 같은 작업을 수행 할 수 있습니다.

first="second" ; second="third" ; third="fourth" ; fourth="fifth"
print ${(P)${(P)${(P)first}}}
fifth

3

eval을 올바르게 사용하고 있지 않습니다. 예를 들어 $ VAR 앞에 "$"(즉,`$ VALUE ')가 명령으로 실행됩니다. 그것은 당신이 원하는 것이 아닙니다. 다른 변수에서 이름을 얻은 변수의 확장을 평가하려고합니다.

$ for i in `echo PATH MAIL EDITOR`; 
    do eval moo="\${$i}" 
    echo $moo 
done
/usr/local/sbin:/usr/local/bin:/usr/sbin:/u (...)
/var/mail/root
nano

0

{ba,z}sh 해결책

다음은 {ba, z} sh에서 모두 작동하는 함수입니다. POSIX 와도 호환됩니다.

주어진 경우 경고합니다 :

  • 널 입력
  • 하나 이상의 논쟁
  • 설정되지 않은 변수 이름

# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
var_expand() {
  if [ "$#" -ne 1 ] || [ -z "${1-}" ]; then
    printf 'var_expand: expected one non-empty argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}

POSIX function도 없습니다 . [[...]]sh
Stéphane Chazelas

인수가 없는지 확인해야합니다 [ "$#" -eq 0 ](또는 아마도 [ "$#" -ne 1 ]하나의 인수 만 예상하는 경우).
Stéphane Chazelas

@ StéphaneChazelas 감사합니다. POSIX 준수를위한 참조 셸이 있습니까? 나도 shell-check도움이 될 것 같아요 .
Tom Hale

@ StéphaneChazelas 테스트를 다시 수행하면 단일 null 인수가 주어지면 실패하고 싶습니다. 두 번째 제안을 추가했습니다. 건배!
Tom Hale

${1-}주어진 a='"" -o -n 1' [ -z $a ]== 인용에 동의합니다 0. 그러나 $#항상 단일 토큰이 아닐까요?
Tom Hale
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.