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

2019-01-07 03:11发布

问题:

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.

回答1:

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

head -n -2 myfile.txt


回答2:

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 looing for.



回答3:

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'


回答4:

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)


回答5:

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!



回答6:

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



回答7:

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 !!)



回答8:

This might work for you (GNU sed):

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


回答9:

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


回答10:

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.



回答11:

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".



回答12:

Try the following command:

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


回答13:

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

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



回答14:

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


回答15:

I prefer this solution;

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

where N is the number of lines to remove.



回答16:

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

posix version



回答17:

To delete last 4 lines:

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


回答18:

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


回答19:

This will remove the last 3 lines from file:

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



回答20:

This will remove the last 12 lines

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