sed在OSX插入的特定行


24

所以我在Linux上使用'sed'已有一段时间了,但是由于'POSIX sed'和'GNU sed'的差别很小,因此尝试在OSX上使用它有点困难。目前,我正在努力在特定行号后插入一行文本。(在这种情况下,第4行)

在linux上,我会这样做:

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

因此,在OSX上,我尝试了以下操作:

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

但是,这总是给我“命令末尾\后面的多余字符”错误。有什么主意吗?我有错字吗?还是我不了解sed版本之间的另一个区别?


2
可以确认这在MacOS 10.6.8上不起作用。在debian 6.0.3上工作正常。
2012年

Answers:


24

严格来说,的POSIX规范在以下位置sed需要换行符a\

[1addr]a\
text

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

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

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

因此,为了便于携带sed语法,您将需要在a\某种程度上添加换行符。最简单的方法是插入带引号的换行符:

$ sed -e 'a\
> text'

(其中$>是shell提示)。如果您发现很痛苦,则bash[1]具有$' '用于插入C样式转义符的引用语法,因此只需使用

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

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


非常有用的答案。感谢您对bash引用语法的提示。
cjackson

14

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

在这种情况下,您实际上想用一个-e ...子句完成您想做的事情。您只需要a正确使用该命令即可。按照POSIX标准,a需要在其后跟一个\,然后再需要一个换行符,然后将插入下一行的其余部分(直到遇到换行符或该-e子句的末尾)。因此,您可以执行以下操作:

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

2
如果您想弄清您所依赖的Gnu- isms功能,此页面可能会有所帮助:wiki.alpinelinux.org/wiki/Regex。不过,它仅限于正则表达式功能;而不是其他sed命令。
dubiousjim 2012年

5

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

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

您可以选择$ brew install gnu-sed,也可以使用来获取所有常见的GNU实用程序$ brew install coreutils

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


5

Perl不受此类平台相关的GNU,非GNU和“专有”特质的困扰。您可以这样做:

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

-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,因此简单替换等的语法并不是很陡的学习曲线。


好答案!但是您可以稍微简化一下。试试这个: perl -wlpi.old -e 'print "mode 0755" if $. == 5' file.txt。该-p交换机的工作原理以及在这里(因为我们想打印每行); 我们只需将逻辑从“ 第4行之后打印”更改为“ 第5行之前打印”。并进行-l切换,以便每个都自动打印“ \ n” print,因此您不必自己打印。
JL
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.