使用bash / sed搜索和替换文件中的变量

时间:2012-03-29 15:24:31

标签: bash sed

我正在尝试编写一个bash脚本(script.sh)来搜索和替换in​​put.sh文件中的一些变量。但是我只需要修改variable_list文件中存在的变量,并保留其他变量。

variable_list

${user}  
${dbname}

input.sh

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表达式

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"    

4 个答案:

答案 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}