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

Dot*_*tan 3 sed

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

这是我到目前为止:

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

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

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

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

然而放在一起是行不通的。这就像函数总是返回一个空字符串。

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

ilk*_*chu 5

该命令行将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
Run Code Online (Sandbox Code Playgroud)

(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
Run Code Online (Sandbox Code Playgroud)