mezda
mezda

Reputation: 3637

How to use sed to remove the last n lines of a file

I want to remove some n lines from the end of a file. Can this be done using sed?

For example, to remove lines from 2 to 4, I can use

$ sed '2,4d' file

But I don't know the line numbers. I can delete the last line using

$sed $d file

but I want to know the way to remove n lines from the end. Please let me know how to do that using sed or some other method.

Upvotes: 207

Views: 312778

Answers (26)

qstebom
qstebom

Reputation: 739

From the sed one-liners:

# delete the last 10 lines of a file
sed -e :a -e '$d;N;2,10ba' -e 'P;D'   # method 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba'  # method 2

Seems to be what you are looking for.

Upvotes: 44

ams
ams

Reputation: 25559

I don't know about sed, but it can be done with head:

head -n -2 myfile.txt

Upvotes: 285

Kajukenbo
Kajukenbo

Reputation: 275

POSIX compliant solution using ex / vi, in the vein of @Michel's solution above. @Michel's ed example uses "not-POSIX" Here-Strings. Increment the $-1 to remove n lines to the EOF ($), or just feed the lines you want to (d)elete. You could use ex to count line numbers or do any other Unix stuff.

Given the file:

cat > sometextfile <<EOF
one
two
three
four
five
EOF

Executing:

ex -s sometextfile <<'EOF'
$-1,$d
%p
wq!
EOF

Returns:

one
two
three

This uses POSIX Here-Docs so it is really easy to modify - especially using set -o vi with a POSIX /bin/sh. While on the subject, the "ex personality" of "vim" should be fine, but YMMV.

Upvotes: 0

user2928048
user2928048

Reputation: 4118

Say you have several lines:

    $ cat <<EOF > 20lines.txt
> 1
> 2
> 3
[snip]
> 18
> 19
> 20
> EOF

Then you can grab:

# leave last 15 out
$ head -n5 20lines.txt
1
2
3
4
5

# skip first 14
$ tail -n +15 20lines.txt
15
16
17
18
19
20

Upvotes: 0

JRichardsz
JRichardsz

Reputation: 16495

In docker, this worked for me:

head --lines=-N file_path > file_path

Upvotes: 0

Zac
Zac

Reputation: 2250

A solution similar to https://stackoverflow.com/a/24298204/1221137 but with editing in place and not hardcoded number of lines:

n=4
seq $n | xargs -i sed -i -e '$d' my_file

Upvotes: 0

Sherlock Holmes
Sherlock Holmes

Reputation: 1

#!/bin/sh

echo 'Enter the file name : '
read filename

echo 'Enter the number of lines from the end that needs to be deleted :'
read n

#Subtracting from the line number to get the nth line
m=`expr $n - 1`

# Calculate length of the file
len=`cat $filename|wc -l`

#Calculate the lines that must remain
lennew=`expr $len - $m`

sed "$lennew,$ d" $filename

Upvotes: 0

Alessandra Bilardi
Alessandra Bilardi

Reputation: 352

For deleting the last N lines of a file, you can use the same concept of

$ sed '2,4d' file

You can use a combo with tail command to reverse the file: if N is 5

$ tail -r file | sed '1,5d' file | tail -r > file

And this way runs also where head -n -5 file command doesn't run (like on a mac!).

Upvotes: -1

lzc
lzc

Reputation: 949

Use sed, but let the shell do the math, with the goal being to use the d command by giving a range (to remove the last 23 lines):

sed -i "$(($(wc -l < file)-22)),\$d" file

To remove the last 3 lines, from inside out:

$(wc -l < file)

Gives the number of lines of the file: say 2196

We want to remove the last 23 lines, so for left side or range:

$((2196-22))

Gives: 2174 Thus the original sed after shell interpretation is:

sed -i '2174,$d' file

With -i doing inplace edit, file is now 2173 lines!

If you want to save it into a new file, the code is:

sed -i '2174,$d' file > outputfile

Upvotes: 31

R. Kumar
R. Kumar

Reputation: 109

This will remove the last 12 lines

sed -n -e :a -e '1,10!{P;N;D;};N;ba'

Upvotes: -2

Gilles Qu&#233;not
Gilles Qu&#233;not

Reputation: 184955

A funny & simple sed and tac solution :

n=4
tac file.txt | sed "1,$n{d}" | tac

NOTE

  • double quotes " are needed for the shell to evaluate the $n variable in sed command. In single quotes, no interpolate will be performed.
  • tac is a cat reversed, see man 1 tac
  • the {} in sed are there to separate $n & d (if not, the shell try to interpolate non existent $nd variable)

Upvotes: 29

Rey Lefebvre
Rey Lefebvre

Reputation: 21

It can be done in 3 steps:

a) Count the number of lines in the file you want to edit:

 n=`cat myfile |wc -l`

b) Subtract from that number the number of lines to delete:

 x=$((n-3))

c) Tell sed to delete from that line number ($x) to the end:

 sed "$x,\$d" myfile

Upvotes: 2

Kamil Christ
Kamil Christ

Reputation: 354

To truncate very large files truly in-place we have truncate command. It doesn't know about lines, but tail + wc can convert lines to bytes:

file=bigone.log
lines=3
truncate -s -$(tail -$lines $file | wc -c) $file

There is an obvious race condition if the file is written at the same time. In this case it may be better to use head - it counts bytes from the beginning of file (mind disk IO), so we will always truncate on line boundary (possibly more lines than expected if file is actively written):

truncate -s $(head -n -$lines $file | wc -c) $file

Handy one-liner if you fail login attempt putting password in place of username:

truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure

Upvotes: 10

user5780554
user5780554

Reputation: 11

This will remove the last 3 lines from file:

for i in $(seq 1 3); do sed -i '$d' file; done;

Upvotes: 1

Michel
Michel

Reputation: 1523

Just for completeness I would like to add my solution. I ended up doing this with the standard ed:

ed -s sometextfile <<< $'-2,$d\nwq'

This deletes the last 2 lines using in-place editing (although it does use a temporary file in /tmp !!)

Upvotes: 13

coyotetechy
coyotetechy

Reputation: 1

I came up with this, where n is the number of lines you want to delete:

count=`wc -l file`
lines=`expr "$count" - n`
head -n "$lines" file > temp.txt
mv temp.txt file
rm -f temp.txt

It's a little roundabout, but I think it's easy to follow.

  1. Count up the number of lines in the main file
  2. Subtract the number of lines you want to remove from the count
  3. Print out the number of lines you want to keep and store in a temp file
  4. Replace the main file with the temp file
  5. Remove the temp file

Upvotes: 0

Rishav Kaushal
Rishav Kaushal

Reputation: 19

Try the following command:

n = line number
tail -r file_name | sed '1,nd' | tail -r

Upvotes: 1

mstafreshi
mstafreshi

Reputation: 1

To delete last 4 lines:

$ nl -b a file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//'   

Upvotes: 0

NeronLeVelu
NeronLeVelu

Reputation: 10039

sed -n ':pre
1,4 {N;b pre
    }
:cycle
$!{P;N;D;b cycle
  }' YourFile

posix version

Upvotes: 0

user1170868
user1170868

Reputation:

Most of the above answers seem to require GNU commands/extensions:

    $ head -n -2 myfile.txt
    -2: Badly formed number

For a slightly more portible solution:

     perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;'

OR

     perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}'

OR

     awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }'

Where "10" is "n".

Upvotes: 5

p014k
p014k

Reputation: 11

I prefer this solution;

head -$(gcalctool -s $(cat file | wc -l)-N) file

where N is the number of lines to remove.

Upvotes: 0

Kyle
Kyle

Reputation: 639

If hardcoding n is an option, you can use sequential calls to sed. For instance, to delete the last three lines, delete the last one line thrice:

sed '$d' file | sed '$d' | sed '$d'

Upvotes: 46

SWW13
SWW13

Reputation: 63

You can get the total count of lines with wc -l <file> and use

head -n <total lines - lines to remove> <file>

Upvotes: 1

potong
potong

Reputation: 58351

This might work for you (GNU sed):

sed ':a;$!N;1,4ba;P;$d;D' file

Upvotes: 5

Rishabh Sagar
Rishabh Sagar

Reputation: 1814

With the answers here you'd have already learnt that sed is not the best tool for this application.

However I do think there is a way to do this in using sed; the idea is to append N lines to hold space untill you are able read without hitting EOF. When EOF is hit, print the contents of hold space and quit.

sed -e '$!{N;N;N;N;N;N;H;}' -e x

The sed command above will omit last 5 lines.

Upvotes: 2

richard
richard

Reputation: 309

You could use head for this.

Use

$ head --lines=-N file > new_file

where N is the number of lines you want to remove from the file.

The contents of the original file minus the last N lines are now in new_file

Upvotes: 22

Related Questions