替换先前声明的变量中的变量

替换先前声明的变量中的变量

这是模板变量 VAR1,需要根据 VAR2 进行更新,变量的顺序如下,如何在没有 sed 命令的情况下更新 VAR1

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

答案1

你可以使用envsubst

(使用任何 POSIX shell,包括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 shell 中,您可以使用 aeval和 here-document 执行类似的操作:

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

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

bash或 的另一个选项zsh是使用printf

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

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

使用zsh(但不使用bash),您可以使用%n$s语法(就像在许多printf(3)实现中一样)来引用nth参数:

#! /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"

或者使用任意命名格式指令(仅限于除, , NUL 和十进制数字zformat之外的单字节字符):-.

#! /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"

使用ksh93,您可以使用%H代替%sin itprintf来正确编码 HTML 中的特殊字符(例如,&变为&amp;),但对于非 ASCII 字符,它只能在使用 iso8859-1 字符集的区域设置中正常工作。ksh93printf支持-v,不过可以用expanded_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

然后,您可以使用shell 变量的xmlstarlet值替换所有th具有文字值的节点的值,如下所示:$var2var2

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

这会xmlstarlet调用 XPATH 查询,选择th我们想要修改的所有节点。 xmlstarlet将用 shell 变量的值替换这些节点的值var2,并将结果写入标准输出。

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

请注意,这将正确编码该值var2以包含到您的 XML 文档中:

$ 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+。

相关内容