0

I'm using sed to do the following:

  • Match pattern (eg: line starting with #)
  • Substitute match (eg: substitute the # char at the start to nothing/remove it)
  • Print to stdout (eg: print the resulting subtitution to stdout, since we're using -i)
  • Delete match (eg: delete the whole line that contained the # char at the start of the line)

This is done on a file, and as such, sed wouldn't output to stdout when used with the -i flag, unless I use the following trick:

sed -i -e 's/^\(#\)/\1/w /dev/stdout' -e '/^#/d' test

on a file called test, with the following example content:

#this
#is
a
test

The above work for everything, except substitution... Here the one implementing substitution (where I try to delete the # character before printing it to stdout):

sed -i -e 's/^\(#\)//w /dev/stdout' -e '/^#/d' test

This is similar to above, except I replaced \1 with // so it delete # instead of printing the whole line...

Problem is, the last one doesn't work in deleting the line, and instead only substitute and print. The first one does work for everything except substitution (eg: removing the # sign at the start of the line)

Why isn't this working (the second attempt that is, first one work except it doesn't delete the # char)?

  • You make an effort to substitute something in a line that starts with a #, then you want to delete it. This is like polishing and filling up your car before sending it to the junkyard. Why not just delete it without substituting it? – berndbausch May 19 '21 at 00:35
  • ...Because I need the output while also deleting said line in said file? I don't think you always need to specify the lengthy reasons why something need/is to be done, especially when there "already": 1. a possibility it can be done easily (or not), 2. work done/trials/errors by the one who asked, 3. Essentially, I already explained the reason why (eg: using -i prevent the output from being shown on stdout, unlike when not using -i...) :) @berndbausch – Nordine Lotfi May 19 '21 at 00:41

2 Answers2

1

The first expression s/^\(#\)//w /dev/stdout removes the thing that the second one /^#/d would have matched.

You could instead use

sed -i -e '/^#/{s///w /dev/stdout' -e 'd}' test

ex.

$ cat test
#this
#is
a
test

$ sed -i -e '/^#/{s///w /dev/stdout' -e 'd}' test this is

$ cat test a test

steeldriver
  • 81,074
1

With GNU awk:

awk  -i inplace '{if (/^#/) {sub(/^#/, "");arr[++i]=$0;} else print}END{for (a in arr) print arr[a]}' input

The option -i or --include is used to include an awk source library inplace.

About inplace read this and this.

The inplace extension emulates GNU sed's -i option, which performs "in-place" editing of each input file.

if (/^#/) this sees if there is a line starting with #. If found sub() replces # with an empty string. And now substituted $0 is taken and an array arr is created. This array is printed in END block so this is printed on screen. Other lines being printed(in main block) are sent to file by inplace.

$ awk  -i inplace '{if (/^#/) {sub(/^#/, "");arr[++i]=$0;} else print}END{for (a in arr) print arr[a]}' input
this
is

$ cat input a test