Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to approximate the computer's write speed using dd:

dd if=/dev/urandom of=/dev/null bs=1K count=10000

which gives the following output

10000+0 records in
10000+0 records out
10240000 bytes (10 MB) copied, 0.746313 s, 13.7 MB/s

How can I get the '13.7 MB/s' into a bash variable? I've tried piping the output from dd to progs like awk, sed and grep to no avail.

Ultimately, I'm calling this via os.system(...) from within a python script. If anyone knows of a more direct way to get a similar result inside python I'd be interested in that also. I'm trying to predict how long a file copy will take, based on the file size.

Any help would be greatly appreciated.

share|improve this question
    
Have a look at File descriptors & shell scripting – Ulrich Dangel Jul 24 '12 at 22:12
up vote 8 down vote accepted

The problem is your designated output from dd goes to STDERR and not STDOUT so you have to redirect STDERR as well and not only STDOUT.

For bash and zsh you can use |& instead of | which will also redirect STDERR to STDIN of the second command, e.g:

dd if=/dev/urandom of=/dev/null bs=1K count=10000 |& awk '/copied/ {print $8 " "  $9}'

The more general approach is to redirect STDERR explicitly with 2>&1, e.g:

dd if=/dev/urandom of=/dev/null bs=1K count=10000 2>&1 | awk '/copied/ {print $8 " "  $9}'

For the python part have a look at at the subprocess module and Popen in particular.

share|improve this answer
    
Thanks very much, it worked a treat! – James Jul 24 '12 at 22:16
var=$(dd if=/dev/urandom of=/dev/null bs=1K count=10000 2>&1)
var=$(echo ${var##*,})
share|improve this answer

Since Bash parameter expansion avoids the use of external commands, it is a good and elegant solution that 1_CR proposed.

However his proposition returns the wrong value (i.e. only the value behind the comma):

$ var=$(dd if=/dev/urandom of=/dev/null bs=1K count=10000 2>&1)
$ var=$(echo ${var##*,})
$ echo $var
8 MB/s # the wrong value

While the following right answer would give:

$ var=$(dd if=/dev/urandom of=/dev/null bs=1K count=10000 2>&1)
$ var=$(echo ${var##*s,})
$ echo $var
11,8 MB/s # the right value
share|improve this answer
    
That's because the decimal separator is the comma in your locale. By changing it to s,, you're moving the problem to locales where the word for seconds doesn't start with s (Russian, Japanese, Hungarian...). – Stéphane Chazelas Feb 3 '15 at 15:50
    
Yes you are right! I didn't see that. Do you have a solution whatever the locale set? – denaitre Feb 3 '15 at 16:03

Another variation on the theme, getting all pertinent fields, avoiding external calls to awk or sed (uses read, which in bash is a built in)

IFS=' +' read in_full in_part _x _x \
out_full out_part _x _x \
bytes _x _x _x _x seconds _x speed speed_units < <(
  echo $(dd if=/dev/zero of=/dev/null bs=1024 count=7 2>&1) 
)

echo -e "$bytes bytes were read in $seconds seconds, speed was $speed $speed_units.\n$in_full full blocks, and $in_part partial blocks were read in.\n$out_full full blocks, and $out_part partial blocks were written out."

The same thing in one line (without \ line breaks)

IFS=' +' read in_full in_part _x _x out_full out_part _x _x bytes _x _x _x _x seconds _x speed speed_units < <( echo $(dd if=/dev/zero of=/dev/null bs=1024 count=7 2>&1) )
echo -e "$bytes bytes were read in $seconds seconds, speed was $speed $speed_units.\n$in_full full blocks, and $in_part partial blocks were read in.\n$out_full full blocks, and $out_part partial blocks were written out."
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.