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
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityIt 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.
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...
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.
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?
May 26, 2022 at 23:02