Bash 用另一个文件的内容替换文件中的分隔文本块

Bash 用另一个文件的内容替换文件中的分隔文本块,bash,shell,scripting,sed,awk,Bash,Shell,Scripting,Sed,Awk,我需要编写一个简单的脚本,用另一个文件的内容替换配置文件中的一块文本 让我们假设具有以下简化文件: server.xml <?xml version='1.0' encoding='UTF-8'?> <Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <Connector port="80" protocol="HTTP/1.1"/> <En

我需要编写一个简单的脚本,用另一个文件的内容替换配置文件中的一块文本

让我们假设具有以下简化文件:

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 className="org.apache.catalina.realm.UserDatabaseRealm"
       resourceName="UserDatabase"/>
我想运行一个脚本,让
realm.xml
替换
行之间的内容。如果
realm.xml
发生更改,则每当脚本再次运行时,它都会用
realm.xml
的新内容再次替换这些行。这是为了在域不同的多个安装上启动服务时在
/etc/init.d/tomcat
中运行

我不太确定我怎么能简单地用
awk
sed

TOTAL_line=`cat server.xml | wc-l来做到这一点`
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
BEGIN_LINE=`grep-n-e''server.xml | cut-d:-f 1` END_LINE=`grep-n-e''server.xml | cut-d:-f 1` 尾线=$($总线-$尾线)) head-n$BEGIN\u LINE server.xml>server2.xml cat realm.xml>server2.xml tail-n$tail_LINES server.xml>server2.xml
(好的,这不使用awk或sed…我假设这不是唯一的要求:-)

您可以使用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
awk'FNR==NR{{{++d]=$0;next}
/开始王国/{
打印

对于(i=1;i我创建的这个小片段怎么样:

sed -n \
  -e "1,/<\!-- BEGIN realm -->/ p" \
  -e"/<\!-- END realm -->/,$ p" \
  -e "/<\!-- BEGIN realm -->/ r realm.xml" \
  server.xml
sed-n\
-e“1,//p”\
-e“/,$p”\
-e”//r realm.xml“\
server.xml
第一个命令打印到
的行,第二个命令打印从
开始的行,第三个命令将文本附加到文件“realm.xml”中。如果我能简化删除
之间的行而不删除标记行,那就简单多了可以用sed在
本地
完成!!!

尝试一下:

sed -i -ne '/<!-- BEGIN realm -->/ {p; r realm.xml' -e ':a; n; /<!-- END realm -->/ {p; b}; ba}; p' server.xml
sed-i-ne'/{p;r realm.xml'-e':a;n;/{p;b};ba};p'server.xml

您也可以使用ed命令(cf.):

cat我也遇到了同样的需求(因此找到了这个问题)。在与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

python我无法让Dennis解决方案轻松在OS X上运行(其BSD sed稍有不同)。我找到了另一个解决方案,我可以在Linux和OS X上运行(我有一个混合环境)。上的原始版本仅在Linux上运行,我在这里修复了它:

lead='^<!-- BEGIN realm -->$'
tail='^<!-- END realm -->'
sed  -e '/'"$lead"'/,/'"$tail"'/{ /'"$lead"'/{p; r realm.xml' -e' }; /'"$tail"'/p; d;} '  server.xml

这两个代码都在标准输出上打印输出。使用重定向,或者,要替换文件内联,请添加选项“-i”(在linux上)或“-i”“(在BSD/OS X上)。

这不是唯一的要求;-)是否有效?总计行的值将包含字符串“server.xml”在大多数版本的wc中,我怀疑算法会失败。这似乎是正确的方法,但它非常神秘。你能提供一些线索来说明它是如何工作的吗?如何改变它,使它可以像“sed-I”一样在原地进行替换?您只需要重定向到temp文件并重新命名它。那么
呢?您的sed命令不会替换
。当我在linux机器上运行它时,它会替换。此外,如果您运行命令时没有最后一个脚本(-e)它提供的
server.xml
没有所有的
。在Ubuntu Precision上对我不起作用。插入文本但不删除…哇…它起作用了。我正试图掌握分支的窍门,以便真正理解发生了什么。
ba
分支,在与“开始”测试相关的大括号内标记“a”当找到“end”时,
b
分支到末尾,因为它位于与该测试相关联的一组大括号中。这有点像
if/BEGIN/then read file;而不是/end/do skip line
。我得到了一个语法错误:
sed:-e expression#1,char 39:unexpected
”`@SteveBennett:the-I需要独立。折叠时(如在
-ine
中),它将
ne
视为备份文件的后缀,并且无法看到导致错误的第一个
-e
子句。我已经更正了我的答案。就像一个符咒一样,如果你有一个变量包含文件名,其中的文本将被读取为单引号,那么就使用双引号来禁用shell扩展。
lead='^<!-- BEGIN realm -->$'
tail='^<!-- END realm -->'
sed  -e '/'"$lead"'/,/'"$tail"'/{ /'"$lead"'/{p; r realm.xml' -e' }; /'"$tail"'/p; d;} '  server.xml
sed -ne '/'"$lead"'/ {
 p
 r realm.xml
 :a
 n 
 /'"$tail"'/ {
  p
  b
 } 
 ba
 }
p' server.xml