我想在任何现有的#include之前,用一个额外的include指令更新大量的c++源文件。对于这类任务,我通常使用带有sed的小型bash脚本来重写文件。

我如何得到sed替换一个文件中字符串的第一次出现,而不是替换每一次出现?

如果我用

sed s/#include/#include "newfile.h"\n#include/

它替换所有#includes。

我们也欢迎为达到同样目的而提出的其他建议。


当前回答

作为一种替代建议,您可能希望查看ed命令。

man 1 ed

teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'

# for in-place file editing use "ed -s file" and replace ",p" with "w"
# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
   H
   /# *include/i
   #include "newfile.h"
   .
   ,p
   q
EOF

其他回答

只需要在最后加上出现的次数:

sed s/#include/#include "newfile.h"\n#include/1

作为一种替代建议,您可能希望查看ed命令。

man 1 ed

teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'

# for in-place file editing use "ed -s file" and replace ",p" with "w"
# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
   H
   /# *include/i
   #include "newfile.h"
   .
   ,p
   q
EOF

使用FreeBSD ed,避免ed在文件中没有include语句时出现“no match”错误:

teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'

# using FreeBSD ed
# to avoid ed's "no match" error, see
# *emphasized text*http://codesnippets.joyent.com/posts/show/11917 
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
   H
   ,g/# *include/u\
   u\
   i\
   #include "newfile.h"\
   .
   ,p
   q
EOF

我需要一个在GNU和BSD上都可以工作的解决方案,而且我也知道第一行永远不会是我需要更新的一行:

sed -e "1,/pattern/s/pattern/replacement/"

尝试//特性不重复模式对我不起作用,因此需要重复它。

如果有人来这里替换所有行中第一次出现的字符(比如我自己),使用这个:

sed '/old/s/old/new/1' file

-bash-4.2$ cat file
123a456a789a
12a34a56
a12
-bash-4.2$ sed '/a/s/a/b/1' file
123b456a789a
12b34a56
b12

例如,通过将1改为2,你可以只替换所有的第二个a。