以前に宣言された変数の変数を置き換える

以前に宣言された変数の変数を置き換える

これは、VAR2に従って更新する必要があるテンプレート変数VAR1です。変数の順序は次のとおりです。 sedコマンドなしでVAR1を更新する方法は?

#!/bin/bash
VAR1="<tr>
    <th>\$VAR2</th>
  </tr>"
VAR2=test
echo $VAR2

答え1

あなたが使用できるenvsubst

(付属のPOSIXシェルを使用してくださいbash):

VAR1="<tr>
    <th>\$VAR2</th>
  </tr>"
VAR2=test

expanded_VAR1=$(
  export VAR2
  printf '%s\n' "$VAR1" |
    envsubst '$VAR2'
)

または、すべての単語拡張(パラメータ拡張、コマンド置換、算術拡張)を実行します。~上zshパラメータ拡張の場合は、対応するeパラメータ拡張フラグを使用できます。

#!/bin/zsh -
VAR1="<tr>
    <th>\$VAR2</th>
  </tr>"
VAR2=test

expanded_VAR1=${(e)VAR1}

POSIXシェルでは、evalhere-documentを使用して同様の操作を実行できます。

VAR1="<tr>
    <th>\$VAR2</th>
  </tr>"
VAR2=test

expanded_VAR1=$(eval "cat << EOF
$VAR1
EOF")

bashまたはのもう1つのオプションは、次のものを使用することzshですprintf

VAR1='<tr>
    <th>%s</th>
  </tr>'
VAR2=test

printf -v expanded_VAR1 -- "$VAR1" "$VAR2"

zsh(使用しない)を使用すると、次の構文を使用してthパラメータを参照bashできます%n$s(多くの実装と同様)。printf(3)n

#! /bin/zsh -
VAR1='<tr>
    <th>%1$s</th> <th>%1$s again</th> <th>%2$s</th>
  </tr>'
VAR2=test VAR3=test2

printf -v expanded_VAR1 -- "$VAR1" "$VAR2" "$VAR3"

または、名前付き形式ディレクティブを使用します(zformat、、NUL、および10進数を除く単一バイト文字に制限されています)。-.

#! /bin/zsh -
VAR1='<tr>
    <th>%a</th> <th>%a again</th> <th>%b</th>
  </tr>'
VAR2=test VAR3=test2

zformat -f expanded_VAR1 "$VAR1" "a:$VAR2" "b:$VAR3"

を使用すると、代わりにを使用してHTMLの特殊文字(beなど)を正しくエンコードできますが、ksh93ASCII以外の文字の場合は、iso8859-1文字セットを使用するロケールでのみ正しく機能します。サポートされていませんが機能します。%H%sprintf&&amp;ksh93printf-vexpanded_VAR1=${ printf... ;}

/メソッドを使用すると、printfテンプレートのリテラル文字をzformatエスケープできます(次のように)、/ +here-docメソッドを使用すると/ /プレフィックスを付けてエスケープできます。それからAFAIK、脱出口はありません。%%%\\\printfeeval$`\\envsubst$

答え2

パラメータ拡張を使用して、var1の一意の文字列をvar2の値に置き換えることができます。

var1='<tr>
    <th>unique_placeholder_var2</th>
  </tr>'
var2=test
echo "${var1/unique_placeholder_var2/"$var2"}"

答え3

var1正しい形式のXMLが含まれているとします。

var1='
<tr>
  <th>$var2</th>
</tr>
'

var2=test

xmlstarletその後、すべてのノードの値をth次のようにシェル変数の値としてリテラル値に置き換えることができます。$var2var2

var1=$( printf '%s\n' "$var1" | xmlstarlet ed -u '//th[text() = "$var2"]' -v "$var2" )

これは、変更するすべてのノードを xmlstarlet選択するためにXPATHクエリを呼び出します。このノードの値はシェル変数の値に置き換えられ、結果は標準出力に書き込まれます。thxmlstarletvar2

$ printf '%s\n' "$var1"
<?xml version="1.0"?>
<tr>
  <th>test</th>
</tr>

これは、var2XML文書に含める値を正しくエンコードします。

$ var1='
<tr>
  <th>$var2</th>
</tr>
'
$ var2='HÉLLO :->'
$ var1=$( printf '%s\n' "$var1" | xmlstarlet ed -u '//th[text() = "$var2"]' -v "$var2" )
$ printf '%s\n' "$var1"
<?xml version="1.0"?>
<tr>
  <th>H&#xC9;LLO :-&gt;</th>
</tr>

答え4

テンプレート内の変数を置き換える一般的な方法:

  • bash正規表現を使用して変数名をキャプチャします(欲張り一致のため、ここでは変数名が右から左に一致します)。
  • 変数を使用して間接的に変数値を取得する
  • 無限ループを回避するには、入力文字列から一致するvarnameを削除します(これを行うと元の文字列が破損するため、必要に応じてバックアップしてください)。

デモ

  1. 置き換えるテンプレートと(すべてではない)変数を設定します。

    VAR1="<tr>
        <th>\$VAR2</th>
        <th>\$VAR3</th>
      </tr>"
    VAR2=test
    unset VAR3
    
  2. 交換の実行

    result=""
    while [[ $VAR1 =~ (.*)\$([[:alpha:]_][[:alnum:]_]*)(.*) ]]; do
        varname=${BASH_REMATCH[2]}
        [[ -v $varname ]] && replacement=${!varname} || replacement="\$${varname}"
        result="${replacement}${BASH_REMATCH[3]}${result}"
        VAR1=${BASH_REMATCH[1]}
    done
    result="${VAR1}${result}"
    declare -p result
    
  3. 検査結果

    declare -- result="<tr>
        <th>test</th>
        <th>\$VAR3</th>
    </tr>"
    

これを行うには、-vオペレータはbashバージョン4.3+を使用する必要があります。

関連情報