How can I delete the lines starting with "//" (e.g., file header) which are at the beginning of a file?

Viewed 143

I want to delete the header from all the files, and the header has the lines starting with //.

If I want to delete all the lines that starts with //, I can do following:

sed '/^\/\//d'

But, that is not something I need to do. I just need to delete the lines in the beginning of the file that starts with //.

Sample file:

// This is the header
// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

Expected output:

print "Hi"
// This should not be deleted
print "Hello"

Update: If there is a new line in the beginning or in-between, it doesn't work. Is there any way to take care of that scenario?

Sample file:

< new empty line >
// This is the header
< new empty line >
// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

Expected output:

print "Hi"
// This should not be deleted
print "Hello"

Can someone suggest a way to do this? Thanks in advance!

Update: The accepted answer works well for white space in the beginning or in-between.

6 Answers

Could you please try following. This also takes care of new line scenario too, written and tested in https://ideone.com/IKN3QR

awk '
(NF == 0 || /^[[:blank:]]*\/\//) && !found{
  next
}
NF{
  found=1
}
1
' Input_file

Explanation: Simply checking conditions if a line either is empty OR starting from // AND variable found is NULL then simply skip those lines. Once any line without // found then setting variable found here so all next coming lines should be printed from line where it's get set to till end of Input_file printed.

With sed:

sed -n '1{:a; /^[[:space:]]*\/\/\|^$/ {n; ba}};p' file
print "Hi"
// This should not be deleted
print "Hello"

Slightly shorter version with GNU sed:

sed -nE '1{:a; /^\s*\/\/|^$/ {n; ba}};p' file

Explanation:

1 { # execute this block on the fist line only
    :a; # this is a label
     /^\s*\/\/|^$/ { n;  # on lines matching `^\s*\/\/` or `^$`, do: read the next line
          ba }           # and go to label :a
};  # end block
p   # print line unchanged:
    # we only get here after the header or when it's not found

sed -n makes sed not print any lines without the p command.

Edit: updated the pattern to also skip empty lines.

I sounds like you just want to start printing from the first line that's neither blank nor just a comment:

$ awk 'NF && ($1 !~ "^//"){f=1} f' file
print "Hi"
// This should not be deleted
print "Hello"

The above simply sets a flag f when it finds such a line and prints every line from then on. It will work using any awk in any shell on every UNIX box.

Note that, unlike some of the potential solutions posted, it doesn't store more than 1 line at a time in memory and so will work no matter how large your input file is.

It was tested against this input:

$ cat file

    // This is the header

// This should be deleted
print "Hi"
// This should not be deleted
print "Hello"

To run the above on many files at once and modify each file as you go is this with GNU awk:

awk -i inplace 'NF && ($1 !~ "^//"){f=1} f' *

and this with any awk:

ip_awk() { local f t=$(mktemp) && for f in "${@:2}"; do awk "$1" "$f" > "$t" && mv -- "$t" "$f"; done; }

ip_awk 'NF && ($1 !~ "^//"){f=1} f' *

In case perl is available then this may also work in slurp mode:

perl -0777 -pe 's~\A(?:\h*(?://.*)?\R+)+~~' file

\A will only match start of the file and (?:\h*(?://.*)?\R+)+ will match 1 or more lines that are blank or have // with optional leading spaces.

With GNU sed:

sed -i -Ez 's/^((\/\/[^\n]*|\s*)\n)+//' file

The ^((\/\/[^\n]*|\s*)\n)+ expression will match one or more lines starting with //, also matching blank lines, only at the start of the file.

Using ed (the file editor that the stream editor sed is based on),

printf '1,/^[^/]/ g|^\(//.*\)\{0,1\}$| d\nw\n' | ed tmp.txt

Some explanations are probably in order.

ed takes the name of the file to edit as an argument, and reads commands from standard input. Each command is terminated by a newline. (You could also read commands from a here document, rather than from printf via a pipe.)

  1. 1,/^[^/]/ addresses the first lines in the file, up to and including the first one that does not start with /. (All the lines you want to delete will be included in this set.)
  2. g|^\(//.*\)\{0,1\}$|d deletes all the addressed lines that are either empty or do start with //.
  3. w saves the changes.

Step 2 is a bit ugly; unfortunately, ed does not support regular expression operators you may take for granted, like ? or |. Breaking the regular expression down a bit:

  1. ^ matches the start of the line.
  2. //.* matches // followed by zero or more characters.
  3. \(//.*\)\{0,1\} matches the preceding regular expression 0 or 1 times (i.e., optionally)
  4. $ matches the end of the line.
Related