使用bash/sed在文件中查找和替换变量

9

我正在尝试编写一个bash脚本(script.sh),来在input.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个回答

4
这可能会起作用:
#!/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
这里有一个可用的 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关键字也是不必要的,除非它被用于一些未显示的子进程中。

2
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

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}

(mapcar (op list @1 (second [find vars @1 equal first])) entries) 的意思是“通过一个函数将 entries 的元素映射到一个由变量和将该变量替换为 var 列表中的结果组成的两个元素列表中。” [find vars @1 equal first] 意味着在使用 equal 作为比较(适用于字符串)的情况下,在 vars 中查找匿名函数(条目)的第一个参数(@1),并使用每个条目的第一个元素作为键(因为条目是两个元素列表,第一个元素是键)。find 返回一对,因此 (second ...) 获取值。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接