Replace delimited block of text in file with the contents of another file

后端 未结 7 782
无人及你
无人及你 2020-12-09 06:32

I need to write a simple script to replace a block of text in a configuration file with the contents of another file.

Let\'s assume with have the following simplifie

相关标签:
7条回答
  • 2020-12-09 06:45

    How about this little snippet I created:

    sed -n \
      -e "1,/<\!-- BEGIN realm -->/ p" \
      -e"/<\!-- END realm -->/,$ p" \
      -e "/<\!-- BEGIN realm -->/ r realm.xml" \
      server.xml
    

    The first commands prints the lines up to <!- BEGIN realm --> the second command prints the line starting at <!-- END realm --> and the third commands append the text in the file 'realm.xml'. If only I could simplify the removing of the lines between <!- BEGIN realm --> and <!-- END realm --> without removing the marker lines it would as simple as it gets. And it can be done inplace with sed!!!

    0 讨论(0)
  • 2020-12-09 06:45

    I ran into this same need (hence finding this question). After messing around with sed and awk for far too long, I eventually realised there's nothing wrong with using a modern, readable, understandable, widely available language like 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
    

    I think sed and awk have had their day. They were useful once upon a time, but very few people can read or write either without documentary assistance these days.

    (Source: the internet)

    0 讨论(0)
  • 2020-12-09 06:46

    you can use 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 is passed to awk as the first file. FNR==NR means getting the records of the first file passed in and store to variable _. awk will process the next file once FNR!=NR. if awk finds /BEGIN realm/, print the BEGIN realm line, then print what is stored in _. By setting a flag (f) to 1, the rest of the lines after BEGIN realm will not be printed until /END realm/ is detected.

    0 讨论(0)
  • 2020-12-09 06:54

    Give this a try:

    sed -i -ne '/<!-- BEGIN realm -->/ {p; r realm.xml' -e ':a; n; /<!-- END realm -->/ {p; b}; ba}; p' server.xml
    
    0 讨论(0)
  • 2020-12-09 06:55

    You may also use the ed command (cf. 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
    
    0 讨论(0)
  • 2020-12-09 07:00

    I was unable to get Dennis solution easily working on OS X (its BSD sed is slightly different). I found this other solution that I was able to make work on both Linux and OS X (I have a mixed environment). The original version on superuser.com works only on Linux, here I fixed it:

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

    Here a version of Dennis code that works also on OS X (using multiple lines):

    sed -ne '/'"$lead"'/ {
     p
     r realm.xml
     :a
     n 
     /'"$tail"'/ {
      p
      b
     } 
     ba
     }
    p' server.xml
    

    Both these codes print the output on stdout. Use redirection or, to substitute the file inline, add the option '-i' (on linux) or '-i ""' (on BSD/OS X).

    0 讨论(0)
提交回复
热议问题