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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21876431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 09:37:33  来源:igfitidea点击:

Replace text between two strings in file using linux bash

linuxbashsed

提问by Kriss

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. I have tried many solutions from this forum but none of them works.

我需要用异常文件的内容替换 #start_exceptions 和 #end_exceptions 之间的所有内容。我从这个论坛尝试了很多解决方案,但没有一个有效。

回答by Mark Setchell

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. It starts at the beginning as 1, so all lines are printed till I find a line starting with #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.

p 是一个标志,表示是否打印行。它从 1 开始,所以打印所有行,直到我找到以 #start 开头的行。然后我查看异常文件的内容并停止打印行,直到找到以#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. And it also deletes everything between /#start/ and /#end/.

当它找到 /^#end/ 时,它会读入异常文件。它还会删除/#start/ 和/#end/ 之间的所有内容。

I have left the matching slightly "loose" for clarity of expressing the technique.

为了表达技术的清晰性,我让匹配稍微“松散”。

回答by fedorqui 'SO stop harming'

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.txtperforms the two actions.
  • /end/ {r exceptions\n}if the line contains end, then read the file exceptionsand append it.
  • /start/,/end/ {d}from a line containing startto a line containing end, delete all the lines.
  • sed $'one_thing; another_thing' ac1.txt执行这两个动作。
  • /end/ {r exceptions\n}如果该行包含end,则读取文件exceptions并附加它。
  • /start/,/end/ {d}从包含的行start到包含的行end,删除所有行。

回答by claydonkey

I had problem with Mark Setchell's solution in 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...

我在 MINGW 中对 Mark Setchell 的解决方案有疑问。插入符号没有拾取行的开头。实际上,分隔符的检测是否取决于它位于行首?我想出了这个 awk 替代方案......

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