使用shell脚本替换文件中的标记

时间:2018-06-08 22:00:37

标签: linux bash shell awk sed

我有一个包含令牌变量的文件。当我们切换环境时,我们想要为我们所处的环境正确替换这些令牌。

如何在Linux shell中执行此操作?我在想awk或sed。

示例:

文件包含以下数据:

DB_HOST=__HOST__
DB_PASSWORD=__PASSWORD__

我想阅读此文件,识别__HOST__并将其替换为环境变量$(HOST)。我们将从两个下划线之间的匹配字符串中获取环境变量名称。

有没有人知道我们该如何做到这一点?

3 个答案:

答案 0 :(得分:3)

程序envsubst是为了这个目的而设计的,但它希望使用标准的shell格式来从环境中替换字符串:

# Here-doc delimiter quoted to avoid having the shell do the substitutions
$ HOST=myhost PASSWORD=secret envsubst <<"EOF"
DB_HOST=$HOST
DB_PASSWORD=${PASSWORD}
EOF

DB_HOST=myhost
DB_PASSWORD=secret

envsubst是Gnu gettext的一部分,并且可以广泛使用。如果您确实需要使用__...__语法,则可以通过sed管道将其更改为envsubst语法:

$ cat myfile.txt
DB_HOST=__HOST__
DB_PASSWORD=__PASSWORD__

$ sed -E 's/__(([^_]|_[^_])*)__/${\1}/g' myfile.txt |envsubst

或者,如果你有Python,那么有一个非常简单的解决方案:

from sys import stdin
from os import getenv
import re

pattern = re.compile(r"__(\w*)__")

def replacer(m):
    val = getenv(m[1])
    if val is None:
        # No such environment
        # Perhaps produce a warning, or an error
        # Here we just pass through the string unaltered
        return m[0]
    return val

print(pattern.sub(replacer, stdin.read()))

示例:

$ export HOST=myhost PASSWORD=secret 
$ python3 subst.py < myfile.txt
DB_HOST=myhost
DB_PASSWORD=secret

这个解决方案的关键是Python(不幸的是只有少数其他语言)允许模式替换的替换参数是一个函数,然后在每次连续匹配时调用它来生成替换文本。这使得在Python中编写这样的函数比在awk中更容易,例如,替换文本是固定的。

答案 1 :(得分:1)

这是m4的意思:

$ export HOST=myhost PASSWORD=mypassword

$ cat myfile
DB_HOST=__HOST__
DB_PASSWORD=__PASSWORD__

$ m4 -D __HOST__="$HOST" -D __PASSWORD__="$PASSWORD" myfile
DB_HOST=myhost
DB_PASSWORD=mypassword

如果你想为所有环境变量自动定义宏,那当然可以稍微不确定:

$ cat mymacros.m4
esyscmd(`env | sed -ne "s/^\([A-Z_]*\)=\(.*\)/define(__\1__, \`\2')/p" | tr -d "\n"')

$ cat myfile2
include(`mymacros.m4')
DB_HOST=__HOST__
DB_PASSWORD=__PASSWORD__
And other arbitrary text containing things like "My editor is __EDITOR__"

$ m4 myfile2
DB_HOST=myhost
DB_PASSWORD=mypassword
And other arbitrary text containing things like "My editor is vim"

这不一定是最简单的方法,但它非常灵活和可扩展,支持条件语句,宏函数等。

答案 2 :(得分:0)

这就是您想要的:

 while IFS= read -r line  || [[ -n "$line" ]]; do
    from=$(echo $line | cut -d '=' -f 1 )
    to=$(echo $line | cut -d '=' -f 2 )
    sedString=${sedString}" s/__${from}__/${to}/g;"
  done < tokenFile.txt

sed "${sedString}" old.txt >> new.txt

它将用tokenFile.txt构建一个包含所有所需替换项的字符串,然后使用一个sed命令一次将所有替换项替换为您指定的任何文件。 tokenFile.txt具有“旧=新”对。 old.txt是带有令牌的文件。 new.txt是您输出的地方。

例如,运行脚本后,您将得到:

$ cat tokenFile.txt
DB_HOST=127.0.0.1

$ cat old.txt
dbconnect __DB_HOST__

$ cat new.txt
dbconnect 127.0.0.1