Acho que isso deve funcionar:
$ # Create test file
$ echo "Hello, World" > h.data
$
$ # Move contents up by 2 bytes
$ # Note if= and of= are the same for in-place editing
$ dd bs=2 if=h.data skip=1 seek=0 conv=notrunc of=h.data
5+1 records in
5+1 records out
11 bytes (11 B) copied, 0.000598796 s, 18.4 kB/s
$
$ # Note 11 bytes were moved above
$ # Truncate the file after byte 11
$ dd bs=11 if=h.data skip=1 seek=1 count=0 of=h.data
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000338852 s, 0.0 kB/s
$
$ # Display edited file:
$ cat h.data
llo, World
$
Resumindo tudo isso em um script, você pode ter algo assim:
#!/bin/bash
size=$(stat -c %s "$2")
dd bs=$1 if="$2" skip=1 seek=0 conv=notrunc of="$2"
dd bs=$((size - $1)) if="$2" skip=1 seek=1 count=0 of="$2"
Chame isso de:
./truncstart.sh 2 file.dat
Em que 2
é o número de bytes a serem excluídos desde o início de file.data
Como aponta @Gilles, essa solução não é robusta em caso de indisponibilidade não planejada, o que poderia ocorrer na metade do processamento de dd
; Nesse caso, o arquivo seria corrompido.