2

In the dd command, we can use skip to skip n byte in a file. From nth byte to end of file is copied. But I want to copy binary data from 1228 to 1331 only. How do I achieve this with dd on Linux?

terdon
  • 242,166
Ashish Pawar
  • 151
  • 2
  • 8

3 Answers3

6

Use the count to specify the number of bytes to copy. Use the shell to do the calculation. Use ibs=1 to set the input block size to 1, so the skip and count are specified in bytes.

 dd ibs=1 skip=1228 count=$((1331-1228+1))

As 1228 and 1331-1228+1 are both multiples of 4 it would be possible to set the input block size to 4, which would make things more efficient but unless this was going to be used an enormous number of times the optimization will be lost in the noise. Other things like pre-calculating the result of 1331-1228+1 should be done first.

 dd ibs=4 skip=$((1228/4)) count=$(((1331-1228+1)/4))
icarus
  • 17,920
0

There's no reason to use dd at all. A simple head and tail combination is enough (requires GNU tools) :

head -c 1331 file | tail -c $((1331-1228+1)) 
terdon
  • 242,166
  • probably -c not -n – frostschutz Sep 25 '19 at 10:07
  • @frostschutz whoops, thanks. I was testing with - n on my machine. – terdon Sep 25 '19 at 10:43
  • @MarkPlotnick true, I forgot to mention that, but the OP is on Linux. – terdon Sep 25 '19 at 10:44
  • The OP is on linux, but you edit the question to delete the linux tag, but your answer depends on common linux extensions??? Perhaps you should revert your edit. – icarus Sep 25 '19 at 11:18
  • @icarus argh, you're quite right, sorry! I removed the tag because tags shouldn't be used to specify the OS (the linux tag would be next to useless in this site since the vast majority of questions are from people running Linux), but I stupidly forgot to add it to the question! Thanks for the reminder. – terdon Sep 25 '19 at 14:44
-1

just finished an common script dd-file-range.sh: dd-file-range.sh

used to copy of a byte range from one file to another.
like syscall copy_file_range(2) on linux kernel-5.3 or FreeBSD-13
see also: linux copye_file_range() and FreeBSD copy_file_range()

and could also use the xfs_io->copy_range sub-command in newer linux distributions instead dd-file-range.sh

Usage:

$ dd-file-range.sh
Usage: dd-file-range.sh <ifile[:skip_offset[:len]]> [ofile[:seek_offset]] [-bs=BSIZE] [-sep=<seperator>] [-log=<0|1|2>]
#Comment: if 'skip_offset' start with '['; trate it as 'start' #((start=skip_offset+1))
#Comment: if 'len' has a suffix ']'; trate it as 'end' #((end=skip_offset+len))
#Comment: e.g: ifile:5:5 <=is equivalent to=> ifile:[6:10]

Examples: dd-file-range.sh ifile:8192:512 ofile dd-file-range.sh ifile::4096 ofile:1024 dd-file-range.sh ifile:4 #output to stdout dd-file-range.sh <(cat):4 ofile #read from stdin dd-file-range.sh ifile::4 ifile:10 #copy data within same file

for the original question, we can use dd-file-range.sh like:

$ dd-file-range.sh kiss-vm:$((1228-1)):$((1331-1228+1))
$ #or simple
$ dd-file-range.sh kiss-vm:[1228:1331]

performance test with different bs:

$ ls -lh kiss-vm.gif 
-rw-r--r-- 1 yjh fs-qe 4.0M May 12  2021 kiss-vm.gif
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=$((128*1024))
real    0m0.023s
user    0m0.005s
sys 0m0.026s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=$((64*1024))
real    0m0.023s
user    0m0.007s
sys 0m0.022s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old #default BS == $((16*1024))
real    0m0.022s
user    0m0.003s
sys 0m0.025s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=$((8*1024))
real    0m0.022s
user    0m0.005s
sys 0m0.023s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=$((4*1024))
real    0m0.023s
user    0m0.008s
sys 0m0.022s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=1024
real    0m0.024s
user    0m0.005s
sys 0m0.028s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=512
real    0m0.039s
user    0m0.006s
sys 0m0.048s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=256
real    0m0.037s
user    0m0.010s
sys 0m0.044s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=128
real    0m0.046s
user    0m0.012s
sys 0m0.057s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=64
real    0m0.072s
user    0m0.011s
sys 0m0.102s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=32
real    0m0.129s
user    0m0.014s
sys 0m0.199s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=16
real    0m0.275s
user    0m0.049s
sys 0m0.425s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=8
real    0m0.460s
user    0m0.077s
sys 0m0.707s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=4
real    0m1.278s
user    0m0.208s
sys 0m2.082s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=2
real    0m1.841s
user    0m0.294s
sys 0m2.846s
$ time dd-file-range.sh kiss-vm.gif:1981 b:1981 -ver=old -bs=1
real    0m3.924s
user    0m0.610s
sys 0m6.227s