sed:用可变内容替换字符串

sed:用可变内容替换字符串

我正在尝试编写一个脚本,该脚本查找特定模式({?varname})中的字符串并将其替换为相应的环境变量。

这是我到目前为止所拥有的:

function get_env() {
   var=$1
   echo ${!var}
}

sed -e 's/{?\([a-z]*}\)/'$(get_env '\1')'/g' file.txt

该功能有效,例如get_env LOGNAME-->dotan

sed 返回函数的值,例如,如果我将函数的内容替换为,echo __$1__我将得到{?logname}-->__LOGNAME__

然而,组合起来却不起作用。就好像函数总是返回一个空字符串。

我不确定是什么导致了这里的问题。有任何想法吗?

答案1

该命令行将get_env '\1'在命令替换中运行,并将其输出粘贴到sed.您可能应该收到一个错误,因为\1不是变量的有效名称。

你可以使用 Perls/\{\?([a-z]+)\}/$ENV{$1}/来做到这一点;%ENV是包含环境变量的哈希:

$ export name=you
$ echo "hello {?name}" | perl -pe 's/\{\?([a-z]+)\}/$ENV{$1}/'
hello you

(GNU sed 有e运行外部程序的命令,但它使用运行整个模式空间,而不仅仅是匹配部分,因此它似乎不太适合这里。)


纯粹在 Bash 中,如果你坚持 ( setvar.sh):

#!/bin/bash
while IFS= read -r line ; do
        while [[ $line =~ ^(.*)(\{\?[a-zA-Z0-9_]+\})(.*)$ ]] ; do
                varname=${BASH_REMATCH[2]}
                varname=${varname#"{?"}
                varname=${varname%\}}
                printf -v line "%s%s%s" "${BASH_REMATCH[1]}" "${!varname}" "${BASH_REMATCH[3]}"
        done
        printf "%s\n" "$line" 
done < "${1-/dev/stdin}"

$ echo 'foo {?BASH_VERSION} {?blah} bar' |blah=ABC bash setvar.sh
foo 4.4.12(1)-release ABC bar

答案2

这是我想出的解决方案

grep -o '{?\S*}' file.txt | sed 's/{?\(.*\)}/\1/' | xargs -I {} sh -c "sed -i -e 's/{?"{}"}/'$"{}"'/' file.txt"

分解它:

  • grep -o '{?\S*}' file.txt- 获取所有要替换的变量
  • sed 's/{?\(.*\)}/\1/'- 删除格式
  • xargs -I {} sh -c "sed -i -e 's/{?"{}"}/'$"{}"'/' file.txt"- 分别搜索和替换每个变量

相关内容