OSX 上的 sed 在某一行插入

OSX 上的 sed 在某一行插入

因此,我在 Linux 上使用“sed”已经有一段时间了,但在 OSX 上使用它时遇到了一些困难,因为“POSIX sed”和“GNU sed”有很多细微的差别。目前我正在努力解决如何在特定行号之后插入一行文本。 (在本例中为第 4 行)

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

sed --in-place "4 a\  mode '0755'" file.txt

所以在 OSX 上我尝试了这个:

sed -i "" "4 a\ mode '0755'" file.txt

然而,这一直给我一个“命令末尾 \ 之后的额外字符”错误。有什么想法这里出了什么问题吗?我有错字吗?或者我不理解 sed 版本之间的另一个区别?

答案1

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

[1addr]a\
text

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

这使得写俏皮话变得有点痛苦,这可能是以下原因GNU 扩展ai、 和c命令:

作为 GNU 扩展,如果a和换行符之间有除空白\序列之外的其他内容,则从 后的第一个非空白字符开始的该行文本a将被视为文本堵塞。 (这可以简化单行添加脚本的编写。)此扩展还可以与ic命令一起使用。

因此,为了与您的语法兼容sed,您需要在后面添加一个换行符a\。最简单的方法是插入带引号的换行符:

$ sed -e 'a\
> text'

(其中$>是 shell 提示符)。如果您发现疼痛,bash[1] 有$' '插入 C 风格转义符的引用语法,所以只需使用

sed -e 'a\'$'\n''text'

[1] 自版本 2.0 (1996) 和 ksh93 (它的来源)、zsh (3.1.5+)、mksh (r39b+) 和一些 Almquist shell 衍生品(例如,FreeBSD 9+ 中的 /bin/sh)

答案2

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

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

sed -i "" -e $'4 a\\\n'"mode '0755'" file.txt

答案3

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

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

-n选项创建一个循环来读取输入文件的每一行。与它的表兄弟-p(此处未使用)不同,它不会自动打印读取的每一行。调用-i就地替换。-i(即“.old”)的参数可以被删除或更改。它会留下未修改文件的备份。标志着-e脚本的开始。

表示$.行号,从第 1 行开始。因此,命令行会读取file,当行号等于 4 时,它会打印该行,然后打印您想要注入的内容。

我想赶紧补充一点,Perl 的根源在于sedawkC,因此简单替换等的语法并不是一个非常陡峭的学习曲线。

答案4

一个简单的演示:

$ date | sed -E $'1i\\\nfoo\n'
foo
Thu Aug  6 07:09:01 CDT 2020

$'...'是强制转义序列扩展的 bashism。使用它时,必须使用来获取字符串中的\\文字。\

相关内容