使用 bash/sed 搜索和替换文件中的变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9928492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Search and replace variables in a file using bash/sed
提问by user1292603
I am trying to write a bash script(script.sh) to search and replace some variables in input.sh file. But I need to modify only the variables which are present in variable_list file and leave others as it is.
我正在尝试编写一个 bash 脚本(script.sh)来搜索和替换 input.sh 文件中的一些变量。但我只需要修改 variable_list 文件中存在的变量,而其他人保持原样。
variable_list
变量列表
${user}
${dbname}
input.sh
输入文件
username=${user}
password=${password}
dbname=${dbname}
Expected output file
预期输出文件
username=oracle
password=${password} > This line won't be changed as this variable(${password}) is not in variable_list file
dbname=oracle
Following is the script I am trying to use but I am not able to find the correct sed expression
以下是我尝试使用的脚本,但我无法找到正确的 sed 表达式
script.sh
脚本文件
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"
采纳答案by FatalError
This could work:
这可以工作:
#!/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/${\([^}]\+\)}//' <<< "$line")
sed -i "s/$exp/${!var}/g" input.sh
fi
done < "$variable"
The first sedexpression escapes the $ which is a regex metacharacter. The second extracts just the variable name, then we use indirection to get the value in our current shell and use it in the sedexpression.
第一个sed表达式转义了 $,它是一个正则表达式元字符。第二个只提取变量名,然后我们使用间接获取当前 shell 中的值并在sed表达式中使用它。
Edit
编辑
Rather than rewriting the file so many times, it's probably more efficient to do it like this, building the arguments list for 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/${\([^}]\+\)}//' <<< "$var")
args+=("-e s/$exp/${!var}/g")
done < "variable_list"
sed "${args[@]}" input.sh > output.sh
回答by jakesandlund
Here is a script.sh that works:
这是一个有效的 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
Note that your original version contains single quotes around the sed string, which doesn't insert the value of $line. It is trying to look for the literal lineafter the end of the line $(which will never find anything).
请注意,您的原始版本在 sed 字符串周围包含单引号,它不会插入$line. 它试图line在行尾$(永远找不到任何东西)之后寻找文字。
Since you are looking for the value of the variable in $line, you need to do an eval to get this.
由于您正在寻找 in 变量的值,因此$line您需要执行 eval 来获得它。
Also, since there are multiple variables you are looping over, the intermediate textvariable stores the result as it loops.
此外,由于您正在循环多个变量,因此中间text变量在循环时存储结果。
The exportkeyword is also unnecessaryin this script, unless it is being used in some sub-process not shown.
该脚本中export也不需要关键字,除非它在某些未显示的子流程中使用。
回答by glenn Hymanman
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
回答by Kaz
TXR solution. Build a filter dynamically. The filter is implemented internally as a trie data structure, which gives us a lex-like state machine which matches the entire dictionary at once as the input is scanned. For simplicity, we include the ${and }as part of the variable name.
TXR 解决方案。动态构建过滤器。过滤器在内部实现为一个特里数据结构,它为我们提供了一个类似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)
Run:
跑:
$ txr subst.txr
username=oracle
password=${password}
dbname=oracle
input.sh:(as given)
input.sh:(如给定)
username=${user}
password=${password}
dbname=${dbname}
variable_list:(as given)
variable_list:(如给定)
${user}
${dbname}

