bash 忽略 SED 中的空格、制表符和新行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37994626/
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 14:48:48  来源:igfitidea点击:

Ignore spaces, tabs and new line in SED

linuxbashsed

提问by krasnoff

I tried to replace a string in a file that contains tabs and line breaks. the command in the shell file looked something like this:

我试图替换包含制表符和换行符的文件中的字符串。shell 文件中的命令如下所示:

FILE="/Somewhere"
STRING_OLD="line 1[ \t\r\n]*line 2"
sed -i 's/'"$STRING_OLD"'/'"$STRING_NEW"'/' $FILE

if I manually remove the line breaks and the tabs and leave only the spaces then I can replace successfully the file. but if I leave the line breaks then SEDis unable to locate the $STRING_OLDand unable to replace to the new string

如果我手动删除换行符和制表符并只留下空格,那么我可以成功替换文件。但是如果我留下换行符,则SED无法找到$STRING_OLD并且无法替换为新字符串

thanks in advance

提前致谢

Kobi

科比

回答by John Bollinger

sedreads lines one at a time, and usually lines are also processed one at a time, as they are read. However, seddoes have facilities for reading additional lines and operating on the combined result. There are several ways that could be applied to your problem, such as:

sed一次读取一行,通常在读取时也一次处理一行。但是,sed确实具有读取附加行和对组合结果进行操作的功能。有几种方法可以应用于您的问题,例如:

FILE="/Somewhere"
STRING_OLD="line 1[ \t\r\n]*line 2"
sed -n "1h;2,$H;${g;s/$STRING_OLD/$STRING_NEW/g;p}"

That that does more or less what you describe doing manually: it concatenates all the lines of the file (but keeps newlines), and then performs the substitution on the overall buffer, all at once. That does assume, however, either that the file is short (POSIX does not require it to work if the overall file length exceeds 8192 bytes) or that you are using a sedthat does not have buffer-size limitations, such as GNU sed. Since you tagged Linux, I'm supposing that GNU sedcan be assumed.

这或多或少地执行您所描述的手动操作:它连接文件的所有行(但保留换行符),然后一次对整个缓冲区执行替换。但是,这确实假设文件很短(如果总文件长度超过 8192 字节,则 POSIX 不需要它工作),或者您使用的sed是没有缓冲区大小限制的文件,例如 GNU sed。既然你标记了 Linux,我假设sed可以假设 GNU 。

In detail:

详细:

  • the -noption turns off line echoing, because we save everything up and print the modified text in one chunk at the end.
  • there are multiple sedcommands, separated by semicolons, and with literal $characters escaped (for the shell):
    • 1h: when processing the first line of input, replace the "hold space" with the contents of the pattern space (i.e. the first line, excluding newline)
    • 2,\$H: when processing any line from the second through the last, append a newline to the hold space, then the contents of the pattern space
    • \${g;s/$STRING_OLD/$STRING_NEW/g;p}: when processing the last line, perform this group of commands: copy the hold space into the pattern space; perform the substitution, globally; print the resulting contents of the pattern space.
  • -n选项关闭行回显,因为我们保存所有内容并在最后将修改后的文本打印在一个块中。
  • 有多个sed命令,用分号分隔,并$转义了文字字符(对于 shell):
    • 1h: 处理输入的第一行时,将“保持空间”替换为模式空间的内容(即第一行,不包括换行符)
    • 2,\$H: 处理从第二行到最后一行的任何一行时,在保持空间中附加一个换行符,然后是模式空间的内容
    • \${g;s/$STRING_OLD/$STRING_NEW/g;p}: 处理最后一行时,执行这组命令:将hold space复制到pattern space;全局执行替换;打印模式空间的结果内容。

That's one of the simpler approaches, but if you need to accommodate seds that are not as capable as GNU's with regard to buffer capacity then there are other ways to go about it. Those start to get ugly, though.

这是一种更简单的方法,但如果您需要适应seds 在缓冲容量方面不如 GNU 的能力,那么还有其他方法可以解决。不过,那些开始变得丑陋。