我需要编写一个简单的脚本,用另一个文件的内容替换配置文件中的文本块。
让我们假设有以下简化文件:
server.xml
<?xml version='1.0' encoding='UTF-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="80" protocol="HTTP/1.1"/>
<Engine name="Catalina" defaultHost="localhost">
<!-- BEGIN realm -->
<sometags/>
<sometags/>
<!-- END realm -->
<Host name="localhost" appBase="webapps"/>
</Engine>
</Service>
</Server>
realm.xml
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
我想运行一个脚本并realm.xml
替换<!-- BEGIN realm -->
和<!-- END realm -->
行之间的内容。如果realm.xml
发生更改,则每当脚本再次运行时,它将再次使用realm.xml
的新内容替换行。这个目的是在启动服务时在/etc/init.d/tomcat
上运行,在多个安装上,域将是不同的。
我不确定如何使用awk
或sed
完成此操作。
答案 0 :(得分:13)
尝试一下:
sed -i -ne '/<!-- BEGIN realm -->/ {p; r realm.xml' -e ':a; n; /<!-- END realm -->/ {p; b}; ba}; p' server.xml
答案 1 :(得分:3)
TOTAL_LINES=`cat server.xml | wc -l`
BEGIN_LINE=`grep -n -e '<!-- BEGIN realm -->' server.xml | cut -d : -f 1`
END_LINE=`grep -n -e '<!-- END realm -->' server.xml | cut -d : -f 1`
TAIL_LINES=$(($TOTAL_LINES-$END_LINE))
head -n $BEGIN_LINE server.xml > server2.xml
cat realm.xml > server2.xml
tail -n $TAIL_LINES server.xml > server2.xml
(好吧,这不使用awk或sed ......我认为这不是一个独家要求: - )
答案 2 :(得分:2)
你可以使用awk
awk 'FNR==NR{ _[++d]=$0;next}
/BEGIN realm/{
print
for(i=1;i<=d;i++){ print _[i] }
f=1;next
}
/END realm/{f=0}!f' realm.xml server.xml > temp && mv temp server.xml
将realm.xml作为第一个文件传递给awk。 FNR == NR表示获取传入的第一个文件的记录并存储到变量_
。一旦FNR!= NR,awk将处理下一个文件。如果awk找到/BEGIN realm/
,请打印BEGIN realm
行,然后打印_
中存储的内容。通过将标志(f)设置为1,BEGIN realm
之后的其余行将不会被打印,直到检测到/END realm/
。
答案 3 :(得分:1)
我创建的这个小片段怎么样:
sed -n \
-e "1,/<\!-- BEGIN realm -->/ p" \
-e"/<\!-- END realm -->/,$ p" \
-e "/<\!-- BEGIN realm -->/ r realm.xml" \
server.xml
第一个命令打印行到<!- BEGIN realm -->
,第二个命令打印从<!-- END realm -->
开始的行,第三个命令将文本附加到文件'realm.xml'中。如果我只是简化删除<!- BEGIN realm -->
和<!-- END realm -->
之间的行而不删除标记行,那么它就会变得简单。它可以用sed !!! {/ 1}完成inplace
答案 4 :(得分:1)
您也可以使用ed命令(参见http://wiki.bash-hackers.org/howto/edit-ed):
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s server.xml
H
/BEGIN realm/i
.
/BEGIN realm/+1,/END realm/-1d
.-1r realm.xml
wq
EOF
答案 5 :(得分:0)
我遇到了同样的需求(因此找到了这个问题)。在用sed和awk搞砸了太久之后,我终于意识到使用像Python这样现代,可读,可理解,广泛使用的语言并没有错:
python <<EOF
import os, sys, re
fname = 'server.xml'
os.rename(fname, fname + '.orig')
with open(fname + '.orig', 'r') as fin, open(fname, 'w') as fout:
data = fin.read()
data = re.sub(r'(<!-- BEGIN realm -->).*?(<!-- END realm -->)',
r'\1\n' +
'insert whatever you want here\n' +
r'\2\n', data, flags=re.DOTALL)
fout.write(data)
EOF
我认为sed和awk度过了他们的一天。它们曾经很有用,但是现在很少有人能够在没有文件帮助的情况下阅读或写作。
(来源:互联网)
答案 6 :(得分:0)
我无法轻易地在操作系统X上使用Dennis解决方案(其BSD sed略有不同)。我找到了另一个解决方案,我能够在Linux和OS X上工作(我有一个混合环境)。 superuser.com上的原始版本仅适用于Linux,我在这里修复了它:
lead='^<!-- BEGIN realm -->$'
tail='^<!-- END realm -->'
sed -e '/'"$lead"'/,/'"$tail"'/{ /'"$lead"'/{p; r realm.xml' -e' }; /'"$tail"'/p; d;} ' server.xml
这里有一个版本的Dennis代码,它也适用于OS X(使用多行):
sed -ne '/'"$lead"'/ {
p
r realm.xml
:a
n
/'"$tail"'/ {
p
b
}
ba
}
p' server.xml
这两个代码都在stdout上打印输出。使用重定向,或者,为了替换内联文件,添加选项'-i'(在linux上)或'-i'“'(在BSD / OS X上)。