如何使用SED修改多个文件中的第n行?

4

我有一些文本文件需要转换为markdown。我想要删除任何前导空格,并在每个文件的第一行添加一个#号。如果我运行以下命令:

sed -i.bak '1s/ *\(.*\)/\#\1/g' *.md

它修改第一个文件的第一行并处理所有文件,而其余文件保持不变。

我错过了什么可以在多个文件的第n行搜索和替换内容?

在OSX 10.7上使用bash。


你的系统上 sed 的版本是多少?它在 Ubuntu 12.04 上运行良好。 - kev
@kev,是这样的--但实际上这与文档中的行为相反,文档表明-s标志应该是必需的,以便将各个文件视为单独的流。话虽如此,OS X不使用GNU工具,因此他可能需要采用shell循环方法。 - Charles Duffy
3个回答

5

问题在于sed默认将任意数量的文件视为单个流,因此行号偏移量相对于第一个文件的开头。

对于GNU sed,您可以使用-s (--separate)标志来修改此行为:

sed -s -i.bak '1s/^ */#/' *.md

如果使用非GNU Sed(包括Mac OS X上的Sed),则可以循环遍历文件并针对每个文件分别调用:

for f in *.md; do sed -i.bak '1s/^ */#/' "$f"; done

请注意,这里的正则表达式有点简化--没有必要匹配您不打算更改的行部分。


谢谢,这正是我需要处理所有文件的东西。我修改了你的第二个答案,将其定位到第一行:对于f in *.md; do sed -i.bak '1s/^ */#/g' "$f"; done - FrederickYocum
@FrederickYocum 感谢您指出这个疏忽;我已经将其作为编辑应用到答案中。 - Charles Duffy

0

XARgs 可以为您解决问题:

http://en.wikipedia.org/wiki/Xargs

从您的sed命令末尾删除*.md,然后使用XArgs逐个收集文件并将它们作为单个实体发送到您的sed命令中。很抱歉我没有时间为您解决问题,但维基百科文章应该会告诉您需要了解的内容。

问题不在于将它们作为单个实体发送到sed - 问题在于sed默认将任意数量的文件视为单个流,因此行号偏移量相对于第一个文件的开头。 - Charles Duffy
@Charles Duffy:请将此内容放入您的答案中。 - Karoly Horvath

0
sed -rsi.bak '1s/^/#/;s/^[ \t]+//' *.md

在命令末尾不需要使用g(全局),因为你想要替换的是行首而非多个位置。

你需要使用两个命令,一个用于修改第一行(1s...),另一个用于带前导空格(和制表符?:=\t)的空白,中间使用分号隔开。如果你需要删除第一行中的空格,可以更改顺序:

sed -rsi.bak 's/^[ \t]+//;1s/^/#/' *.md

如果您不需要它,可以删除 \t。那么您也不需要一个组:
sed -rsi.bak 's/^ +//;1s/^/#/' *.md

-r是一个标志,用于表示正则表达式的特殊处理。在这种情况下,您无需掩盖加号。


这是一个很好的观点 - 问题所使用的英语语言在引导空间修改应用于所有行而不仅仅是第一行方面有歧义(尽管其他回答者包括我自己都采取了相反的意思,“第一行”限制旨在适用于两种变化)。我对从原始作者那里获得关于预期含义的澄清感兴趣。 - Charles Duffy
实际上,我认为问题中的“其余文件不变”这句话与这种解释相矛盾。 - Charles Duffy
啊,现在我明白了。我的理解是“我想要(删除任何前导空格)并且(在每个文件的第一行添加一个井号)”,但是现在你的理解“我想要(删除任何前导空格并在每个文件的第一行添加一个井号)”似乎更有道理,考虑到示例代码。这只涉及sed选项-s。 - user unknown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接