Alex
Alex

Reputation: 21

How to insert a specific character at a specific line of a file using sed or awk?

I want to use command to edit the specific line of a file instead of using vi. This is the thing. If there is a # starting with the line, then replace the # to make it uncomment. Otherwise, add the # to make it comment. I'd like to use sed or awk. But it won't work as expected.
This is the file.

what are you doing now?
what are you gonna do? stab me?
this is interesting.
This is a test.
go big
don't be rude.

For example, I just want to add the # at the beginning of the the line 4 This is a test if it doesn't start with #. And if it starts with #, then remove the #.

I've already tried via sed & gawk (awk)

gawk -i inplace '$1!="#" {print "#",$0;next};{print substr($0,3,length-1)}' file 
sed -i /test/s/^#// file  # make it uncomment

sed -i /test/s/^/#/ file  # make it comment

I don't know how to use if else to make sed work. I could only make it with a single command, then use another regex to make the opposite.
Using gawk, it works as the main line. But it will mess the rest of the code up.

Upvotes: 2

Views: 1922

Answers (4)

potong
potong

Reputation: 58391

This might work for you (GNU sed):

sed '4{s/^/#/;s/^##//}' file

On line 4 prepend a # to the line and if there 2 #'s remove them.

Could also be written:

sed '4s/^/#/;4s/^##//' file

Upvotes: 3

Ed Morton
Ed Morton

Reputation: 203463

$ awk 'NR==4{$0=(sub(/^#/,"") ? "" : "#") $0} 1' file
what are you doing now?
what are you gonna do? stab me?
this is interesting.
#This is a test.
go big
don't be rude.

$ awk 'NR==4{$0=(sub(/^#/,"") ? "" : "#") $0} 1' file |
  awk 'NR==4{$0=(sub(/^#/,"") ? "" : "#") $0} 1'
what are you doing now?
what are you gonna do? stab me?
this is interesting.
This is a test.
go big
don't be rude.

Upvotes: 0

Shawn
Shawn

Reputation: 52354

If you end up on a system with a sed that doesn't support in-place editing, you can fall back to its uncle ed:

ed -s file 2>/dev/null <<EOF
4 s/^/#/
s/^##//
w
q
EOF

(Standard error is redirected to /dev/null because in ed, unlike sed, it's an error if s doesn't replace anything and a question mark is thus printed to standard error.)

Upvotes: 0

John1024
John1024

Reputation: 113834

This will remove # from the start of line 4 or add it if it wasn't already there:

sed -i '4s/^#/\n/; 4s/^[^\n]/#&/; 4s/^\n//' File

The above assume GNU sed. If you have BSD/MacOS sed, some minor changes will be required.

When sed reads a new line, the one thing that we know for sure about the new line is that it does not contain \n. (If it did, it would be two lines, not one.) Using this knowledge, the script works by:

  • s/^#/\n/

    If the fourth line starts with #, replace # with \n. (The \n serves as a notice that the line had originally been commented out.)

  • 4s/^[^\n]/#&/

    If the fourth line now starts with anything other than \n (meaning that it was not originally commented), put a # in front.

  • 4s/^\n//

    If the fourth line now starts with \n, remove it.

Alternative: Modifying lines that contain test

To comment/uncomment lines that contain test:

sed  '/test/{s/^#/\n/; s/^[^\n]/#&/; s/^\n//}' File

Alternative: using awk

The exact same logic can be applied using awk. If we want to comment/uncomment line 4:

awk 'NR==4 {sub(/^#/, "\n"); sub(/^[^\n]/, "#&"); sub(/^\n/, "")} 1' File

If we want to comment/uncomment any line containing test:

awk '/test/ {sub(/^#/, "\n"); sub(/^[^\n]/, "#&"); sub(/^\n/, "")} 1' File

Alternative: using sed but without newlines

To comment/uncomment any line containing test:

sed  '/test/{s/^#//; t; s/^/#/; }' File

How it works:

  • s/^#//; t

    If the line begins with #, then remove it.

    t tells sed that, if the substitution succeeded, then it should skip the rest of the commands.

  • s/^/#/

    If we get to this command, that means that the substitution did not succeed (meaning the line was not originally commented out), so we insert #.

Upvotes: 3

Related Questions