88

I use sed to quickly delete lines with specific position as

sed '1d'
sed '5d'

But, what if I want to delete the last line of the file and I don't know the count of lines (I know I can get that using wc and several other tricks).

Currently, using a workaround with head and tailcombined with wc to do so. Any quick twists here?

Braiam
  • 35,991
mtk
  • 27,530
  • 35
  • 94
  • 130
  • @Nils I am on 'Red Hat Enterprise Linux Server release 5.5 (Tikanga)'. Can you point for the options for head and tail you know of on different flavours? – mtk Nov 19 '12 at 06:39

6 Answers6

153

in sed $ is the last line so to delete the last line:

sed '$d' <file>

Updated to include a way to delete multiple lines from the bottom of the file:

tac <file> | tail -n +3 | tac > <new_file>
  • tac reads the file backwards (cat backwards)
  • tail -n +3 reads the input starting at the nth line
  • tac reads the input and reverses the order back to the original
h3rrmiller
  • 13,235
41

$ for the last line:

sed '$d' file
Guru
  • 5,905
  • 1
    Sadly though one has to use more complex techniques to delete, say, the last two lines. – dubiousjim Oct 24 '12 at 15:13
  • 1
    What do you mean? sed '$d' file; sed '$d' file – Rob Oct 24 '12 at 15:35
  • 4
    @Rob: sed '$d' file doesn't actually modify the file; it just prints out the contents of the file, minus the last line. So sed '$d' file; sed '$d' file will print out the contents of the file twice, minus the last line each time. The delete-the-last-two-lines equivalent of sed '$d' file is sed '$d' file | sed '$d'. – ruakh Oct 24 '12 at 18:48
  • That's what I had originally but changed it because I'm at work on a window box and couldn't check. – Rob Oct 24 '12 at 19:45
  • 2
    Yeah, that's inelegant but of course it works. I would do it in one pass with sed -n '1{h;n;}; $q; x; p;'. I was pouting that we can't just do sed '$-1,$d'. – dubiousjim Oct 24 '12 at 20:24
  • sed -i '$d' file does the trick. – rsuarez Apr 22 '14 at 16:34
  • or sed 'N;$!P;$!D;$d' – Alexej Magura Feb 16 '15 at 23:15
  • somehow your answer didn't work without the top comment's suggestion i.e. without the -i. Why is it? i.e. sed -i '$d' <file> is needed for me. – Charlie Parker Apr 24 '21 at 00:31
  • sed -i ‘$d' helped. "-i" will write automatcially. Thanks for the answer and comment. – user2189731 May 14 '21 at 14:38
16

cat file.txt | head -n -1 > new_file.txt

Beware, it seems, depending on the last line of file.txt (if it ends with EOF, or \n and then EOF), the number of lines in new_file.txt may be the same (as file.txt) after this command (this happens when there is no \n) - in any case, the contents of the last line is deleted.

Also, note that you must use a second (intermediate) file. If you cat and redirect to the same file, you'll erase it.

Emanuel Berg
  • 6,903
  • 8
  • 44
  • 65
  • 8
    Where this works, it could also be simply head -n -1 file.txt > new_file.txt. Note though that negative counts on head -n is only available for some implementations of head. For example, it doesn't work for FreeBSD's or for the BusyBox version of head. – dubiousjim Oct 25 '12 at 09:50
  • 1
    @dubiousjim: Agreed, head -n -1 file.txt > new_file.txt is better. It works the same way with respect to my two comments (same number of lines, and, erase on same file). As for the negative argument, such differences occur from time to time between Unixes, and they are often frustrating because you expect it to be the same command entirely (and why wouldn't you - same name and purpose!) -- anyhow, good point. (I use Debian.) – Emanuel Berg Oct 25 '12 at 17:38
  • head -n -1 doesn't seem to work in zsh. "head: illegal line count -- -1" – John Jiang Mar 08 '22 at 04:02
  • 1
    @JohnJiang It's not the shell that matters, it's the implementation of head. You are most likely not on a GNU system (possibly macOS?). – Kusalananda Jan 24 '23 at 16:18
7

Linux

$ is the last line, d for delete:

sed '$d' ~/path/to/your/file/name

MacOS

Equivalent of the sed -i

sed -i '' -e '$ d' ~/path/to/your/file/name
7

head --lines=-1. I first stumbled across this possibility in the man-page for head on a SLES11SP2-system (coreutils-8.12-6.23.1)

tail and head are part of the coreutils-rpm (at least for rpm-based-systems).

According to the changelog of coreutils, this syntax is supported since coreutils-version 5.0.1

Bad news: According to the RH5-man-page this option is not described

Good news: It works with RH5 (so in your case: it works - at least with a current version of RH5).

rpm -q coreutils shows me (on CentOS 5.8): coreutils-5.97-34.el5_8.1

I am not sure if RH5.5. already has the coreutils-version that supports it. But 5.5 has EoLed anyway.

Nils
  • 18,492
3

On Mac (BSD head/tail) you can use:

cat file.txt | tail -r | tail -n +2 | tail -r
spectrum
  • 213
  • 3
  • 7