Reputation: 3637
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
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
Reputation: 25559
I don't know about sed
, but it can be done with head
:
head -n -2 myfile.txt
Upvotes: 285
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
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
Reputation: 16495
In docker, this worked for me:
head --lines=-N file_path > file_path
Upvotes: 0
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
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
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
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
Reputation: 109
This will remove the last 12 lines
sed -n -e :a -e '1,10!{P;N;D;};N;ba'
Upvotes: -2
Reputation: 184955
A funny & simple sed
and tac
solution :
n=4
tac file.txt | sed "1,$n{d}" | tac
NOTE
"
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
{}
in sed
are there to separate $n
& d
(if not, the shell try to interpolate non existent $nd
variable)Upvotes: 29
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
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
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
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
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.
Upvotes: 0
Reputation: 19
Try the following command:
n = line number
tail -r file_name | sed '1,nd' | tail -r
Upvotes: 1
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
Reputation: 10039
sed -n ':pre
1,4 {N;b pre
}
:cycle
$!{P;N;D;b cycle
}' YourFile
posix version
Upvotes: 0
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
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
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
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
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
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