$ {!FOO}およびzsh


13

${!FOO}で二重置換を実行しますbash。つまり、FOOの(文字列)値を取得し、変数名として使用します。
zshこの機能をサポートしていません。

この作業をbashandで同じにする方法はありzshますか?

バックグラウンド:

次のような環境変数のリストがあります

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)パラメーター拡張フラグは(P)、3.1.5-pws-7(1999)のフラグであるzsh-2.6-beta17(1996年5月)に追加されました。${!var}2.0のbash (1996年12月)。
ステファンシャゼル16年

回答:


18

bashとzshの両方には、間接展開を実行する方法がありますが、異なる構文を使用します。

を使用して間接展開を実行するのは簡単evalです。これは、すべてのPOSIXおよびほとんどのBourneシェルで機能します。値にシェル内で特別な意味を持つ文字が含まれている場合は、適切に引用符を付けてください。

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

${${VAR}}シェルが実装する機能ではないため、機能しません。中括弧内のものは、を含まない構文規則に準拠する必要があります${VAR}。(zshのは、これはサポートされている構文であるが、違うん:ネストされた置換は、同じ値に連続変換を行う。${${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ページ。セクション- パラメーター拡張フラグ

P

  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
ステファンシャゼラス

引数なしのチェックは[ "$#" -eq 0 ](またはおそらく[ "$#" -ne 1 ]1つの引数のみを期待しているように)あるべきです。
ステファンシャゼラス

@StéphaneChazelasありがとう、更新しました。POSIX準拠の参照シェルはありますか?私shell-checkも助けになると思っています。
トム・ヘイル

@StéphaneChazelasテストについて、単一のヌル引数が与えられたときに失敗したいとも思います。2番目の提案を追加しました。乾杯!
トム・ヘイル

== を${1-}指定して引用することに同意します。しかし、常に単一のトークンになるとは限りませんか?a='"" -o -n 1' [ -z $a ]0$#
トム・ヘイル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.