我正在尝试使用sed将%XXX%格式的文件中的模板字符串替换为我的shell脚本中名为XXX的变量的值。
e.g。以下工作完美
sed "s/%user_home%/$user_home/gi"
所以,如果user_home=fred
以下,
NameVirtualHost *:80
<VirtualHost *:80>
ServerName %server_name%
ErrorLog /var/log/apache2/%user_home%_webapp_error.log
CustomLog /var/log/apache2/%user_home%_webapp.log common
DocumentRoot /home/%user_home%/web_app/public
</VirtualHost>
变,
NameVirtualHost *:80
<VirtualHost *:80>
ServerName %server_name%
ErrorLog /var/log/apache2/fred_webapp_error.log
CustomLog /var/log/apache2/fred_webapp.log common
DocumentRoot /home/fred/web_app/public
</VirtualHost>
问题是我想在没有事先明确知道模板字符串及其变量的情况下运行sed命令。也就是说,它会查找%XXX%,然后用$ XXX的内容替换它,而不关心变量的实际名称是什么。
我知道它与反向引用有关但我无法弄清楚如何使用反向引用的内容作为变量名。
我试过了,
sed "s/%\([a-z_]\)%/$(\1)/gi"
但这无效,因为它似乎是在寻找一个名为$ \ 1的变量。
答案 0 :(得分:3)
这里的问题是,当sed
命令实际运行时(因此在检索变量名时),sed
命令必须已完全组装(包括替换)将Bash变量的值放入替换字符串中);所以一切都以错误的顺序发生。
或者,从更高级别的观点来看,问题是sed
不知道Bash变量,所以你需要Bash来提供变量的细节,但是Bash没有了解sed
替换,因此它无法知道您需要哪些变量的详细信息。
只要你想使用Bash变量,修复就是使用更多Bash:你需要在第一次调用sed
之前识别相关的变量名。以下显示了如何做到这一点。
要获取文件中所有变量名的列表,您可以编写如下内容:
grep -o '%[a-z_][a-z_]*%' FILE | grep -o '[a-z_][a-z_]*' | sort -u
(第一个grep
获取表单%...%
的所有表达式。第二个grep
过滤掉百分号;或者您可以使用sed
来表示您更喜欢。sort -u
消除了重复项,因为您只需要 distinct 变量名列表。)
有了这个,您可以组装一个执行所有必要替换的sed
命令:
sed_args=()
while read varname ; do
sed_args+=(-e "s/%$varname%/${!varname}/g")
done < <(grep -o '%[a-z_][a-z_]*%' FILE | grep -o '[a-z_][a-z_]*' | sort -u)
sed "${sed_args[@]}" FILE
(注意使用${!varname}
表示&#34;将$varname
的值作为变量名,并返回该变量的值。&#34;这就是{ {3}}调用&#34;间接扩展&#34;。)
您可以将其包装在一个函数中:
function replace_bash_variables () {
local file="$1"
local sed_args=()
local varname
while read varname ; do
sed_args+=(-e "s/%$varname%/${!varname}/g")
done < <(grep -o '%[a-z_][a-z_]*%' "$file" | grep -o '[a-z_][a-z_]*' | sort -u)
if [[ "${#sed_args[@]}" = 0 ]] ; then
# if no variables to replace, just cat the file:
cat -- "$file"
else
sed "${sed_args[@]}" -- "$file"
fi
}
replace_bash_variables OLD_FILE > NEW_FILE
您还可以调整上述内容以进行逐行处理,这样就不需要两次读取文件。 (这为您提供了更大的灵活性,因为读取文件两次意味着您必须传入实际文件,并且不能(比方说)将此应用于管道的输出。)
答案 1 :(得分:0)
使用awk
可以执行此操作
awk '{gsub(/%user_home%/,"${user_home}")}1' file
NameVirtualHost *:80
<VirtualHost *:80>
ServerName %server_name%
ErrorLog /var/log/apache2/${user_home}_webapp_error.log
CustomLog /var/log/apache2/${user_home}_webapp.log common
DocumentRoot /home/${user_home}/web_app/public
</VirtualHost>
这会将%user_home%
替换为变量${user_home}
答案 2 :(得分:0)
使用此:
sed -E "s/%(\w+)%/\$\1/g"
例如:
echo "abcdef %variable% blah" | sed -E "s/%(\w+)%/\$\1/g"
打印:
abcdef $variable blah
答案 3 :(得分:0)
尝试使用1 sed但仍需要先捕获“set”内容以了解变量名称和值
#!/bin/ksh
# YourFilename contain the file name of your file to treat (here passed as 1st parameter to a script)
YourFileName=$1
(set | sed 's/.*/#V0r:&:r0V#/'; cat ${YourFileName}) | sed -n "
s/$/²/
H
$ {
x
s/^\(\n *\)*//
# also reset t flag
t varxs
:varxs
s/^#V0r:\([a-zA-Z0-9_]\{1,\}\)=\([^²]*\):r0V#²\(\n.*\)%\1%/#V0r:\1=\2:r0V#²\3\2/
t varxs
: tmpb
# clean the line when no more occurance in text
# s/^#V0r:\([a-zA-Z0-9_]\{1,\}\)=\([^²]*\):r0V#²\n//
s/^[^²]*:r0V#²\n//
# and next
t varxs
# clean the marker
s/²\(\n\)/\1/g
s/²$//
# display the result
p
}
"