因此,我在 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 扩展到a
、i
、 和c
命令:
作为 GNU 扩展,如果
a
和换行符之间有除空白\
序列之外的其他内容,则从 后的第一个非空白字符开始的该行文本a
将被视为文本堵塞。 (这可以简化单行添加脚本的编写。)此扩展还可以与i
和c
命令一起使用。
因此,为了与您的语法兼容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 的根源在于sed
、awk
和C
,因此简单替换等的语法并不是一个非常陡峭的学习曲线。
答案4
一个简单的演示:
$ date | sed -E $'1i\\\nfoo\n'
foo
Thu Aug 6 07:09:01 CDT 2020
这$'...'
是强制转义序列扩展的 bashism。使用它时,必须使用来获取字符串中的\\
文字。\