dd
is designed to copy blocks of data from an input file to an output file. The dd
block size options are as follows, from the man page:
ibs=expr
Specify the input block size, in bytes, by expr (default is 512).
obs=expr
Specify the output block size, in bytes, by expr (default is 512).
bs=expr
Set both input and output block sizes to expr bytes, superseding ibs= and obs=.
The dd
seek
option is similar to the UNIX lseek()
system call1. It moves the read/write pointer within the file. From the man page:
seek=n
Skip n blocks (using the specified output block size) from the beginning of the output file before copying.
Ordinary files in UNIX have the convenient property that you do not have to read or write them starting at the beginning; you can seek anywhere and read or write starting from there. So bs=4096 seek=7
means to move to a position 7*4096 bytes from the beginning of the output file and start writing from there. It won't write to the portion of the file that is between 0 and 7*4096 bytes.
Areas of ordinary files that are never written to at all aren't even allocated by the underlying filesystem. These areas are called holes and the files are called sparse files. In your example, file_with_holes
will have a 7*4096-byte hole at the beginning. (h/t @frostschutz for pointing out that dd
truncates the output file by default.)
It is OK to read these unallocated areas; you get a bunch of zeroes.
[1] back when dd
was written, the analogous system call was seek()
.
Solution:
dd if='input_file.bin' \
of='/dev/sd{X}' \
bs={desired write block size} \
seek={start offset in bytes} \
count={write size in bytes} \
oflag=seek_bytes \
iflag=count_bytes
From the man page:
count_bytes
treat 'count=N' as a byte count (iflag only)
...
seek_bytes
treat 'seek=N' as a byte count (oflag only)
This does seem to slow down the transfer a bit, but at least puts it in MB/s, instead of kB/s. Also, be sure to check the man page on your system, as it seems the ones available on the web (i.e. googling 'man dd') don't include these options.
Best Answer
Why the second command outputs a different value?
For historical reasons,
dd
considersx
to be a multiplication operator. So0x3
is evaluated to be 0.Is it possible to pass the skip|seek offset to dd as an hexadecimal value?
Not directly, as far as I know. As well as multiplication using the operator
x
, you can suffix any number withb
to mean "multiply by 512" (0x200) and withK
to mean "multiply by 1024" (0x400). With GNU dd you can also use suffixesM
,G
,T
,P
,E
,Z
andY
to mean multiply by 2 to the power of 20, 30, 40, 50, 60, 70, 80 or 90, respectively, and you can use upper or lower case except for theb
suffix. (There are many other possible suffixes. For example,EB
means "multiply by 1018" andPiB
means "multiply by 250". Seeinfo coreutils "block size"
for more information, if you have a GNU installation.)You might find the above arcane, anachronistic, and geeky to the point of absurdity. Not to worry: you are not alone. Fortunately, you can just ignore it all and use your shell's arithmetic substitution instead (bash and other Posix compliant shells will work, as well as some non-Posix shells). The shell does understand hexadecimal numbers, and it allows a full range of arithmetic operators written in the normal way. You just need to surround the expression with
$((...))
: