Sed-注释与特定字符串 AND 匹配但尚未注释掉的行

我有以下测试文件

AAA
BBB
CCC

使用下面的 sed,我可以注释掉 BBB行。

# sed -e '/BBB/s/^/#/g' -i file

如果行的开头还没有 # ,我只想注释掉它。

# sed -e '/^#/! /BBB/s/^/#/g' file


sed: -e expression #1, char 7: unknown command: `/'

有什么办法能让我做到吗?

118731 次浏览

Assuming you don't have any lines with multiple #s this would work:

sed -e '/BBB/ s/^#*/#/' -i file

Note: you don't need /g since you are doing at most one substitution per line.

I find this solution to work the best.

sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

It doesn't matter how many "#" symbols there are, it will never add another one. If the pattern you're searching for does not include a "#" it will add it to the beginning of the line, and it will also add a trailing space.

If you don't want a trailing space

sed -i '/^[^#]/ s/\(^.*BBB.*$\)/#\1/' file

sed -i '/![^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

This doesn't work for me with the keyword *.sudo, no comments at all...

Ony the syntax below works: sed -e '/sudo/ s/^#*/#/' file

Actually, you don't need the exclamation sign (!) as the caret symbol already negates whatever is inside the square brackets and will ignore all hash symbol from your search. This example worked for me:

sed -i '/[^#]/ s/\(^.*BBB.*$\)/#\ \1/' file

Another solution with the & special character which references the whole matched portion of the pattern space. It's a bit simpler/cleaner than capturing and referencing a regexp group.

sed -i 's/^[^#]*BBB/#&/' file

Assuming the BBB is at the beginning of a line, I ended up using an even simpler expression:

sed -e '/^BBB/s/^/#/' -i file

One more note for the future me. Do not overlook the -i. Because this won't work: sed -e "..." same_file > same_file.

I'd usually supply sed with -i.bak to backup the file prior to making changes to the original copy:

sed -i.bak '/BBB/ s/^#*/#/' file

This way when done, I have both file and file.bak and I can decide to delete file.bak only after I'm confident.

Comment all "BBB", if it's haven't comment yet.

sed -i '/BBB/s/^#\?/#/' file

If you want to comment out not only exact matches for 'BBB' but also lines that have 'BBB' somewhere in the middle, you can go with following solution:

sed -E '/^([^#].*)?BBB/  s/^/#/'

This won't change any strings that are already commented out.

If BBB is at the beginning of the line:

sed 's/^BBB/#&/' -i file

If BBB is in the middle of the line:

sed 's/^[^#]*BBB/#&/' -i file