简体   繁体   English

使用linux bash替换文件中两个字符串之间的文本

[英]Replace text between two strings in file using linux bash

i have file "acl.txt" 我有文件“ acl.txt”

 192.168.0.1
 192.168.4.5
 #start_exceptions
 192.168.3.34
 192.168.6.78
 #end_exceptions
 192.168.5.55

and another file "exceptions" 和另一个文件“例外”

 192.168.88.88
 192.168.76.6

I need to replace everything between #start_exceptions and #end_exceptions with content of exceptions file. 我需要用例外文件的内容替换#start_exceptions和#end_exceptions之间的所有内容。 I have tried many solutions from this forum but none of them works. 我已经尝试过该论坛提供的许多解决方案,但没有一个起作用。

EDITED : 编辑

Ok, if you want to retain the #start and #stop, I will revert to awk: 好的,如果您想保留#start和#stop,我将恢复为awk:

awk '
    BEGIN       {p=1}
    /^#start/   {print;system("cat exceptions");p=0}
    /^#end/     {p=1}
    p' acl.txt

Thanks to @fedorqui for tweaks in comments below. 感谢@fedorqui在下面的评论中进行了调整。

Output: 输出:

192.168.0.1
192.168.4.5
#start_exceptions
192.168.88.88
192.168.76.6
#end_exceptions
192.168.5.55

p is a flag that says whether or not to print lines. p是一个标志,指示是否打印行。 It starts at the beginning as 1, so all lines are printed till I find a line starting with #start. 它从1开始,所以所有行都被打印,直到找到以#start开头的行。 Then I cat the contents of the exceptions file and stop printing lines till I find a line starting with #end, at which point I set the p flag back to 1 so remaining lines get printed. 然后,我整理异常文件的内容并停止打印行,直到找到以#end开头的行,这时我将p标志设置回1,以便剩余的行得以打印。

If you want output to a file, add "> newfile" to the very end of the command like this: 如果要输出到文件,请在命令末尾添加“> newfile”,如下所示:

awk '
    BEGIN       {p=1}
    /^#start/   {print;system("cat exceptions");p=0}
    /^#end/     {p=1}
    p' acl.txt > newfile

YET ANOTHER VERSION IF YOU REALLY WANT TO USE SED 如果您真的想使用SED,还可以使用另一个版本

If you really, really want to do it with sed, you can use nested address spaces, firstly to select the lines between #start_exceptions and #end_exceptions, then again to select the first line within that and also lines other than the #end_exceptions line: 如果确实要使用sed进行操作,则可以使用嵌套的地址空间,首先选择#start_exceptions和#end_exceptions之间的行,然后再次选择其中的第一行以及#end_exceptions行以外的行:

sed '
   /^#start/,/^#end/{
      /^#start/{
         n
         r exceptions
      }
      /^#end/!d
   }
' acl.txt

Output: 输出:

192.168.0.1
192.168.4.5
#start_exceptions
192.168.88.88
192.168.76.6
#end_exceptions
192.168.5.55

ORIGINAL ANSWER 原始答案

I think this will work: 我认为这会起作用:

sed -e '/^#end/r exceptions' -e '/^#start/,/^#end/d' acl.txt

When it finds /^#end/ it reads in the exceptions file. 找到/ ^#end /时,将读取例外文件。 And it also deletes everything between /#start/ and /#end/. 并且还会删除/#start /和/#end /之间的所有内容。

I have left the matching slightly "loose" for clarity of expressing the technique. 为了使该技术清晰明了,我将匹配项保留为“宽松”状态。

You can use the following, based on Replace string with contents of a file using sed : 您可以基于以下内容使用以下内容,使用sed将字符串替换为文件内容

$ sed $'/end/ {r exceptions\n} ; /start/,/end/ {d}' acl.txt
192.168.0.1
192.168.4.5
192.168.88.88
192.168.76.6
192.168.5.55

Explanation 说明

  • sed $'one_thing; another_thing' ac1.txt sed $'one_thing; another_thing' ac1.txt performs the two actions. sed $'one_thing; another_thing' ac1.txt执行两个操作。
  • /end/ {r exceptions\\n} if the line contains end , then read the file exceptions and append it. /end/ {r exceptions\\n}如果该行包含end ,则读取文件exceptions并将其附加。
  • /start/,/end/ {d} from a line containing start to a line containing end , delete all the lines. /start/,/end/ {d}从包含start的行到包含end的行,删除所有行。

I had problem with Mark Setchell's solution in MINGW. 我对Mark Setchell在MINGW中的解决方案有疑问。 The caret was not picking up the beginning of line. 尖号没有出现在行首。 Indeed, is the detection of the separator dependent on it being at the beginning of the line? 确实,是否在行的开头依赖于分隔符的检测? I came up with this awk alternative... 我想出了这个awk替代方案...

$ awk -v data="$(<exceptions)" '
BEGIN {p=1} 
/#start_exceptions/ {print; print data;p=0}
/#end_exceptions/ {p=1}
p
' acl.txt

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM