使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:54:28  来源:igfitidea点击:

Search and replace variables in a file using bash/sed

bashsed

提问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}