sed 在 OSX 上的某一行插入

CRT*_*aze 26 osx sed gnu posix

所以我一直在 linux 上使用 'sed' 一段时间,但是在尝试在 OSX 上使用它时遇到了一些困难,因为 'POSIX sed' 和 'GNU sed' 有很多细微的差别。目前我正在努力解决如何在某个行号后插入一行文本。(在本例中,第 4 行)

在 linux 上,我会做这样的事情:

sed --in-place "4 a\  mode '0755'" file.txt
Run Code Online (Sandbox Code Playgroud)

所以在 OSX 上我试过这个:

sed -i "" "4 a\ mode '0755'" file.txt
Run Code Online (Sandbox Code Playgroud)

但是,这一直给我一个“命令末尾\ 后的额外字符”错误。任何想法这里有什么问题?我有错别字吗?还是我不明白 sed 版本之间的另一个区别?

jw0*_*013 27

严格来说,POSIX 规范sed需要在 之后换行a\

[1addr]a\
text
Run Code Online (Sandbox Code Playgroud)

如前所述将文本写入标准输出。

这使得编写单行有点痛的,这可能是由于以下原因GNU扩展aic命令:

作为 GNU 扩展,如果在a和换行符之间存在非空格\序列,则该行的文本,从 之后的第一个非空格字符开始a,作为文本块的第一行。(这可以简化编写单行添加的脚本。)此扩展也适用于ic命令。

因此,为了让您的sed语法具有可移植性,您需要在a\不知何故之后包含一个换行符。最简单的方法是插入一个带引号的换行符:

$ sed -e 'a\
> text'
Run Code Online (Sandbox Code Playgroud)

(其中$>是 shell 提示)。如果你觉得很痛苦,bash[1] 有$' '插入 C 风格转义的引用语法,所以只需使用

sed -e 'a\'$'\n''text'
Run Code Online (Sandbox Code Playgroud)

[1] 和 mksh (r39b+) 以及一些非 bash bourne shell(例如,FreeBSD 9+ 中的 /bin/sh)


dub*_*jim 14

正如描述的这个答案,它使用sed的命令时,就像是有帮助的i,并a使用多个-e "..."条款。这些子句中的每一个都将被理解为由换行符分隔。该ia命令很难使用内嵌的sed脚本否则(他们是专为多行sed脚本文件使用调用使用sed -f file ...)。看起来您不能使用-e子句末尾引入的隐式换行符来分隔a\要附加的文本行和文本行。但是您可以使用它来终止要附加的文本行。

在这种特定情况下,您尝试执行的操作实际上可能只需要一个-e ...子句即可完成。您只需要a正确使用该命令。根据 POSIX 标准,a需要后跟 a \,然后需要后跟换行符,然后将插入下一行的其余部分(直到遇到换行符或-e子句结尾)。所以你可以这样做:

sed -i "" -e $'4 a\\\n'"mode '0755'" file.txt
Run Code Online (Sandbox Code Playgroud)

  • 如果你想弄清楚你一直依赖的 Gnu-isms 的哪些特性,这个页面可能会有所帮助:http://wiki.alpinelinux.org/wiki/Regex。不过,它仅限于正则表达式功能;不是其他 sed 命令。 (2认同)

小智 6

根据我使用过的示例/教程,GNU sed 似乎比 POSIX sed 更常用。

我发现在我使用的任何 OSX 机器上安装 GNU sed 要容易得多。如果您有兴趣,最好的方法是通过Homebrew安装它。

您可以$ brew install gnu-sed使用$ brew install coreutils.

然后,当您遇到date或其他程序的语法问题时,您可以使用 GNU 版本。最终我决定总是使用 GNU 版本更容易,并将它们放在我的PATH.


JRF*_*son 5

Perl 不会受到这种依赖于平台的 GNU 与非 GNU 与“专有”特性的影响。你可以这样做:

perl -ni.old -e 'print;if ($.==4) {print "mode 0755\n"}' file
Run Code Online (Sandbox Code Playgroud)

-n' option creates a loop that reads every line of the input file. Unlike its cousin-p (not used here) it doesn't automatically print every line read. The-i invokes in-place replacement. The argument to-i(viz. ".old") can be dropped or changed. It leaves a backup of the unmodified file. The -e信号剧本的开头。

$.表示行数,与线-1开始。因此,命令行读取“文件”,当行号等于 4 时,它会打印该行,然后是您想要注入的任何内容。

我想赶紧补充一点,Perl 起源于sed、AWK 和 C,因此简单替换等的语法并不是一个非常陡峭的学习曲线。