21

The first 2 lines in dd stats have the following format:

a+b records in
c+d records out

Why 2 numeric values? What does this plus sign mean? It's usually a+0, but sometimes when I use bigger block size, dd prints 0+b records out

3 Answers 3

17

It means full blocks of that bs size plus extra blocks with size smaller than the bs.

pushd "$(mktemp -d)"
dd if=/dev/zero of=1 bs=64M count=1 # and you get a 1+0
dd if=1 of=/dev/null bs=16M # 4+0
dd if=1 of=/dev/null bs=20M # 3+1
dd if=1 of=/dev/null bs=80M # 0+1
_crap=$PWD; popd; rm -rf "$_crap"; unset _crap
# frostschutz's case
yes | dd of=/dev/null bs=64M count=1 # 0+1

Edit: frostschutz's answer mentions another case to generate non-full blocks. Worth reading. See also https://unix.stackexchange.com/a/17357/73443.

13

0+b records out for b>1 are usually incomplete reads while reading from a pipe or another source that can not provide bs=X of data quickly enough. You can force dd to wait for full blocks of data using iflag=fullblock. This option is particularly useful if you're also using count=X as count also counts incomplete blocks so it's unreliable without fullblock...

5

There are dozens of standard command line utilities that can hang on a descriptor and wait for input. That's pretty much how they all work. dd is unique in that it can show you what a descriptor looks like right now.

Personally, I don't really understand the usefulness behind the GNU iflag=fullblock option. I mean, you can just cat your input at least as easily and without having to worry about i/o block sizes at all.

But dd can take a part of a stream - and it can do it at read()/write() boundaries on a reasonably modern system.

{ (     sleep 1                     #don't write() til dd is definitely setup
        printf 123                  #write() 3  bytes
        printf %-30s\\n 456         #write() 31 bytes
        printf you\ there\?         #write() 10 bytes
)|      dd bs=64 count=2 conv=sync| #2 64 byte read()/write() \0-padded blocks
        od -vtc                     #show it with octal radices
}       2>/dev/null                 #drop stderr

0000000   1   2   3  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000060  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100   4   5   6
0000120                                                          \n  \0
0000140  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000160  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000200

dd does a single read() per input block. If the file it tries to read() does not have as much data as it has requested it doesn't matter - the one read() counts as one block of input. That's how it works - that is dd's primary utility.

When it has done its job, dd reports on all of the input/output blocks it has dealt with. Running the above command again, but dropping stdout instead this time...


dd: warning: partial read (3 bytes); suggest iflag=fullblock
0+2 records in
2+0 records out
128 bytes (128 B) copied, 1.00161 s, 0.1 kB/s

Each time dd did read(0,&in,64) read came back short - because its stdin file descriptor didn't have enough bytes waiting for it to fulfill its request when it made it. And so dd read() 0 full input records, and 2 short ones. That's what those reports mean.

1
  • Does this imply that pipes preserve record boundaries? That is, is the data written by write("123", 3) necessarily consumed by a subsequent read() returning 3 bytes? Or, because of the sleep 1, does the kernel see a reader blocked on the pipe and just forward the write data to the reader instead of buffering it?
    – claymation
    May 26, 2022 at 23:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .