Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

It can be done with other tools, but I am interested to know how can I delete all but the last X lines of the file with sed.

share|improve this question
2  
The hard way. Stick with the other tools. –  Ignacio Vazquez-Abrams Sep 7 '12 at 2:22
add comment

3 Answers

sed is quite complex when it comes to task like this one. tail, grep or awk would make this a lot easier and should be used instead. That being said, it is possible.

The following solution is adapted from sed and Multi-Line Search and Replace.

sed -ni '
    # if the first line copy the pattern to the hold buffer
    1h
    # if not the first line then append the pattern to the hold buffer
    1!H
    # if the last line then ...
    ${
            # copy from the hold to the pattern buffer
            g
            # delete current line if it is followed by at least X more lines
            # replace X-1 with the proper value
            s/.*\n\(\(.*\n\)\{X-1\}\)/\1/
            # print
            p
    }
' filename

Without the comments, it makes a nifty one-liner. If you want to eliminate, e.g., everything but the last ten lines, use this:

sed -ni '1h;1!H;${;g;s/.*\n\(\(.*\n\)\{9\}\)/\1/;p;}' filename
share|improve this answer
    
On non-GNU seds you need -e after -i. –  Matteo Sep 7 '12 at 6:46
    
Just like phiz's answer, this does not handle a request for 0 last lines... However, that is one of the reasons for the recommendation to use another tool. –  Peter.O Sep 7 '12 at 7:49
add comment

Basically you are emulating tail. X = 20 in this example. The following example will delete all but the last 20 lines:

sed -e :a -e '$q;N;21,$D;ba' filename

Explanation:

  • The -e :a creates a label called a
  • The next -e:
    • $q - quits and prints the pattern space if it is the last line
    • N - next line
    • 21,$D - executes the "D" command if the line# is >= 21 (21,$ = 21st line to $ which is the end of the file)
    • ba - branches to label 'a' which is the beginning of the script.
share|improve this answer
    
It works as tail, but I was not able to make it work in place (as the in the original question) –  Matteo Sep 7 '12 at 6:48
1  
+1... BTW. It works with -i if you condense the two -e expressions into one. You can also use it by passing bash variable $1 into it... sed -i ':a;$q;N;'$(($1+1))',$D;ba' filename ... but asking for 0 lines, will return 1 line. –  Peter.O Sep 7 '12 at 7:42
add comment

Based on the script in section 4.13 of the sed.info manual you could do something like this:

n=10

(( n > 1 )) && script='1h; 2,'$n'{H;g;}; $q; 1,'$((n-1))'d; N; D'
(( n > 1 )) || script='$!d'

sed -i "$script" infile
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.