我正在尝试编写一个bash脚本(script.sh)来搜索和替换input.sh文件中的一些变量。但是我只需要修改variable_list文件中存在的变量,并保留其他变量。
${user}
${dbname}
username=${user}
password=${password}
dbname=${dbname}
username=oracle
password=${password} > This line won't be changed as this variable(${password}) is not in variable_list file
dbname=oracle
以下是我尝试使用的脚本,但我无法找到正确的sed表达式
export user=oracle
export password=oracle123
export dbname=oracle
variable='variable_list'
while read line ;
do
if [[ -n $line ]]
then
sed -i 's/$line/$line/g' input.sh > output.sh
fi
done < "$variable"
答案 0 :(得分:2)
这是一个有效的script.sh:
#!/bin/bash
user=oracle
password=oracle123
dbname=oracle
variable='variable_list'
text=$(cat input.sh)
while read line
do
value=$(eval echo $line)
text=$(sed "s/$line/$value/g" <<< "$text")
done < "$variable"
echo "$text" > output.sh
请注意,您的原始版本在sed字符串周围包含单引号,但不会插入$line
的值。它试图在行line
结束后查找文字$
(它永远不会找到任何内容)。
由于您要在$line
中查找变量的值,因此您需要执行eval来获取此值。
此外,由于循环有多个变量,因此中间text
变量会在循环时存储结果。
此脚本中的export
关键字也是unnecessary,除非它在某些未显示的子流程中使用。
答案 1 :(得分:2)
这可行:
#!/bin/bash
export user=oracle
export password=oracle123
export dbname=oracle
variable='variable_list'
while read line ;
do
if [[ -n $line ]]
then
exp=$(sed -e 's/\$/\\&/g' <<< "$line")
var=$(sed -e 's/\${\([^}]\+\)}/\1/' <<< "$line")
sed -i "s/$exp/${!var}/g" input.sh
fi
done < "$variable"
第一个sed
表达式转义$是一个正则表达式元字符。第二个只提取变量名,然后我们使用间接获取当前shell中的值并在sed
表达式中使用它。
修改强>
不是这么多次重写文件,这样做可能更有效率,构建sed
的参数列表:
#!/bin/bash
export user=oracle
export password=oracle123
export dbname=oracle
while read var
do
exp=$(sed -e 's/\$/\\&/g' <<< "$var")
var=$(sed -e 's/\${\([^}]\+\)}/\1/' <<< "$var")
args+=("-e s/$exp/${!var}/g")
done < "variable_list"
sed "${args[@]}" input.sh > output.sh
答案 2 :(得分:1)
user=oracle
password=oracle123
dbname=oracle
variable_list=( '${user}' '${dbname}' )
while IFS="=$IFS" read variable value; do
for subst_var in "${variable_list[@]}"; do
if [[ $subst_var = $value ]]; then
eval "value=$subst_var"
break
fi
done
printf "%s=%s\n" "$variable" "$value"
done < input.sh > output.sh
答案 3 :(得分:0)
TXR解决方案。动态构建过滤器。过滤器在内部实现为trie数据结构,它为我们提供了一个类似lex
的状态机,它可以在扫描输入时立即匹配整个字典。为简单起见,我们将${
和}
作为变量名称的一部分。
@(bind vars (("${user}" "oracle")
("${dbname}" "oracle")
("${password}" "letme1n")))
@(next "variable_list")
@(collect)
@entries
@(end)
@(deffilter subst . @(mapcar (op list @1 (second [find vars @1 equal first]))
entries))
@(next "input.sh")
@(collect)
@line
@ (output :filter subst)
@line
@ (end)
@(end)
执行命令
$ txr subst.txr
username=oracle
password=${password}
dbname=oracle
input.sh:
(如给定的)
username=${user}
password=${password}
dbname=${dbname}
variable_list:
(如给定的)
${user}
${dbname}