You can do it with losetup
, as an alternative to the dd
method described here. Again, this method is dangerous all the same.
Again, the same test file and sizes (remove lines 1-300 from 1000 lines file):
$ seq 1 1000 > 1000lines.txt
$ stat -c %s 1000lines.txt
3893 # total bytes
$ head -n 300 1000lines.txt | wc -c
1092 # first 300 lines bytes
$ echo $((3893-1092))
2801 # target filesize after removal
Create a loop device:
# losetup --find --show 1000lines.txt
/dev/loop0
losetup: 1000lines.txt: \
Warning: file does not fit into a 512-byte sector; \
the end of the file will be ignored.
# head -n 3 /dev/loop0
1
2
3
# tail -n 3 /dev/loop0
921
922
923
Whoops. There are numbers missing. What's going on?
Loop devices require their backing files to be multiple of sector size. Text files with lines don't usually fit that scheme, so in order to not miss the end of file (last partial sector) content, just append some more data first, then try again:
# head -c 512 /dev/zero >> 1000lines.txt
# losetup --find --show 1000lines.txt
/dev/loop1
losetup: 1000lines.txt: \
Warning: file does not fit into a 512-byte sector; \
the end of the file will be ignored.
# tail -n 3 /dev/loop1
999
1000
\0
The warning persists but the content is complete now, so that's okay.
Create another one, this time with the 300 line offset:
# losetup --find --show --offset=1092 1000lines.txt
/dev/loop2
losetup: 1000lines.txt: \
Warning: file does not fit into a 512-byte sector; \
the end of the file will be ignored.
# head -n 3 /dev/loop2
301
302
303
# tail -n 3 /dev/loop2
999
1000
\0
Here's the nice thing about loop devices. You don't have to worry about truncating the file by accident. You can also easily verify that your offsets are indeed correct before performing any action.
Finally, just copy it over, from offset device to full:
cp /dev/loop2 /dev/loop1
Dissolve loop devices:
losetup -d /dev/loop2 /dev/loop1 /dev/loop0
(Or: losetup -D
to dissolve all loop devices.)
Truncate the file to target filesize:
truncate -s 2801 1000lines.txt
The result:
$ head -n 3 1000lines.txt
301
302
303
$ tail -n 3 1000lines.txt
998
999
1000
| gunzip > newfile
but you can just use it with| tail -n +300000001 > newfile
instead. – frostschutz Sep 22 '20 at 07:46scp
the file to a different machine with a larger storage, fixing the file, and copying it back. – choroba Sep 22 '20 at 08:19