Vishal Patel
Vishal Patel

Reputation: 45

How to delete top and last non empty lines of the file

I want to delete top and last non empty line of the file.

Example:

cat test.txt

//blank_line
abc
def
xyz
//blank_line
qwe
mnp
//blank_line

Then output should be:

def
xyz
//blank_line
qwe

I have tried with commands

sed "$(awk '/./{line=NR} END{print line}' test.txt)d" test.txt

to remove last non empty line. At here there are two command, (1) sed and (2) awk. But I want to do by single command.

Upvotes: 1

Views: 326

Answers (5)

potong
potong

Reputation: 58440

This might work for you (GNU sed):

sed -E '0,/\S/d;H;$!d;x;s/.(.*)\n.*\S.*/\1/' file

Use a range to delete upto and including the first line containing a non-space character. Then copy the remains of the file into the hold space and at the end of file use substitution to remove the last line containing a non-space character and any empty lines to the end of the file.

Alternative:

sed '0,/\S/d' file | tac | sed '0,/\S/d'| tac

Upvotes: 0

oguz ismail
oguz ismail

Reputation: 50775

A single-pass, fast and relatively memory-efficient approach utilising a buffer:

awk 'f {
    if(NF) {
        printf "%s",buf
        buf=""
    }
    buf=(buf $0 ORS)
    next
}
NF {
    f=1
}' file

Upvotes: 2

karakfa
karakfa

Reputation: 67507

here is a golfed version of @kvantour's solution

$ awk 'NR==(n=FNR){e=!NF?e:n;b=!b?e:b}b<n&&n<e' file{,}

Upvotes: 0

kvantour
kvantour

Reputation: 26481

This is a double pass method:

 awk '(NR==FNR) { if(NF) {t=FNR;if(!h) h=FNR}; next}
      (h<FNR && FNR<t)' file file

The integers h and t keep track of the head and the tail. In this case, empty lines can also contain blanks. You could replace if(NF) by if(length($0)==0) to be more strict.

This one reads everything into memory and does a simple replace at the end:

$ awk '{b=b RS $0}
       END{ sub(/^[[:blank:]\n]*[^\n]+\n/,"",b);
            sub(/\n[^\n]+[[:blank:]\n]*$,"",b);
            print b }' file

Upvotes: 3

Ed Morton
Ed Morton

Reputation: 203684

Reading the whole file in memory at once with GNU sed for -E and -z:

$ sed -Ez 's/^\s*\S+\n//; s/\n\s*\S+\s*$/\n/' test.txt
def
xyz

qwe

or with GNU awk for multi-char RS:

$ awk -v RS='^$' '{gsub(/^\s*\S+\n|\n\S+\s*$/,"")} 1' test.txt
def
xyz

qwe

Both GNU tools accept \s and \S as shorthand for [[:space:]] and [^[:space:]] respectively and GNU sed accepts the non-POSIX-sed-standard \n as meaning newline.

Upvotes: 3

Related Questions