开发者

Struggling to parse (bash) time command

I'm struggling to parse the output of the time command in bash - and even to stop it from printing out its output when I call it. This is my test code:

#!/bin/bash
TIME=`time ls -lh > /dev/null`
echo "Testing..."
echo $TIME

This currently prin开发者_如何转开发ts out:

{blank-line}
real    0m0.064s
user    0m0.002s
sys     0m0.005s
Testing
{blank-line}

So, it seems like the value assigned to $TIME is the blank line at the start of the time print-out. I need to get at the seconds value of the sys line - that is, the "0.005". I am guaranteed that I will only ever have seconds, so I do not need anything before the "m" - however, the seconds part may be in the form of xx.xxx if it goes >= 10 seconds. I currently have no idea how to suppress the 'time' output, capture it all instead of the blank line, nor parse it to get the values I need.

Any help would be much appreciated...


If you use the Bash builtin time, you can control its output by setting the TIMEFORMAT variable:

TIMEFORMAT=%R

and you won't have to do any parsing since that will cause time to only output the number of seconds.

and use this:

echo "Testing..."
TIME=$( { time ls -lh > /dev/null; } 2>&1 )
echo $TIME

or one of the other techniques from BashFAQ/032.


First and foremost, the data you're trying to capture is being written to standard error. But capturing that output is fairly tricky in this case.

time is both an executable (in /usr/bin) as well as built-in shell command in bash and other shells. When you execute time without specifying /usr/bin/time, you are executing a built-in command in bash. This makes it hard to do things with the output, since bash does not treat it like a normal program; it's a special built-in function written by bash.

Knowing that, and looking at the man page for time(1), I can see that the data you're trying to capture from time is outputted to stderr. So my workaround for this is to directly execute /usr/bin/time as follows:

TIME=`/usr/bin/time ls -lh 2>&1 >/dev/null`

This copies the standard error stream to standard out, and then redirects what normally goes to standard out to /dev/null. Standard error, however, will still go to standard out since it was duplicated before the redirection. Reversing the order of these will not work. (Yes, this is confusing.)

Unfortunately, /usr/bin/time is a bit less precise in its output:

    0.00 real         0.00 user         0.00 sys

Alternatively, you can use 2 sub-shells, as follows:

TIME=$((time ls -lh >/dev/null) 2>&1)

This would re-write what is written to standard error on the second subshell within the first, allowing you to capture the output. See http://www.tldp.org/LDP/abs/html/subshells.html for more on sub-shells.


Although Solutions hover around the same logic, but still I couldn't find following listed, so another version of the solution:

TIME=$(time (ls -lh >/dev/null) 2>&1)


The time command outputs the timing information to STDERR, which you aren't capturing or redirecting. So at the time of the assignment, that information is printed out to your console, while the $TIME variable gets the STDOUT of the command - which you redirected to /dev/null, so it's blank.

Perhaps you should try to capture the STDERR of the command?


I wanted to post this as a comment, but it would be too long. I wanted to present another slightly different way to obtain the data.

You can use the two sub-shells to get the output of time as a stream using /bin/sh rather than /usr/bin/time to obtain the timing of the execution. I imagine you can substitute time here with /usr/bin/time.

$ ((time ./print_test.sh > deleteme) 2>&1) > deletemetime

$ cat deleteme
test

$ cat deletemetime
./print_test.sh > deleteme  0.00s user 0.00s system 86% cpu 0.003 total

$ ((time ./print_test.sh > deleteme) 2>&1) | sed 's/system/kernel/'
./print_test.sh > deleteme  0.00s user 0.00s kernel 86% cpu 0.003 total

Note also that there appears to be a difference in the way it will produce output. Sometimes it is in that format and sometimes it is in this format:

real    0m0.420s
user    0m0.385s
sys     0m0.040s

Not sure at this point what determines one way or the other.

Of course, you can use e.g.

TIMEFORMAT='%3R' 

to fix the format.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜