Why does time ls | grep real output this

real    0m0.002s
user    0m0.000s
sys     0m0.002s

instead of just

real    0m0.002s

If I type

echo -e 'real\t0m0.002s\nuser\t0m0.000s\nsys\t0m0.002s\n' | grep real

I get what I expect, i.e.

real    0m0.002s

I found that this works

(time ls)  2>&1 > /dev/null | grep real

What does this command do?

  • Because time is calculating the elapsed time for ls | grep real not for ls?
    – DavidPostill
    Apr 2 '18 at 15:39
  • woah!!!!!!!!!!!!!!!!!!
    – Nisba
    Apr 2 '18 at 15:45
  • Writing answer.
    – DavidPostill
    Apr 2 '18 at 15:46
  • actually a=$(time ls); echo $a|grep real leads to the same problem
    – Nisba
    Apr 2 '18 at 15:47
  • See my updated answer which explains why it didn't work and how your new command gets around the problem.
    – DavidPostill
    Apr 2 '18 at 16:07

Why does time ls | grep real not work as expected.

time is a bash reserved word and behaves differently than /usr/bin/time.

If the time reserved word precedes a pipeline, the elapsed as well as user and system time consumed by its execution are reported when the pipeline terminates.

Source bash(1): GNU Bourne-Again SHell - Linux man page

In addition, time outputs to standard error not standard output.

Use the following command:

(time ls) 2>&1 >/dev/null | grep real 


  • The ( and ) groups the time and ls commands together (so these commands get evaluated first)

  • 2>&1 >/dev/null first redirects stderr to stdout (which is the pipe) and then redirects stdout to /dev/null.

    So stderr goes to the pipe and stdout goes nowhere.

Further Reading


Yes, it works, but it require a bit of I/O redirection :)

$ exec 3>&1 4>&2
{ time sleep 1 1>&3 2>&4; } 2>&1 |
    grep 'real'    
exec 3>&- 4>&-

Output :

real    0m1,003s

Read bash FAQ#32 and I/O redirection tutorial

A quite simpler way :

$ time sleep 1
  • is this arab language?
    – Nisba
    Apr 2 '18 at 16:03
  • This is bash I/O redirection ^^ Apr 2 '18 at 16:04
  • can you explain me what is going on?
    – Nisba
    Apr 2 '18 at 16:05
  • Check the linked page Apr 2 '18 at 16:05
  • 1
    Added simplest method Apr 2 '18 at 16:07

Two issues here.

First and most important, "time" send it's output to stderr (standard error) not stdout, so that it will not be captured by normal redirection commands unless you take special measures.

Second, time is not a normal program but a special built-in command interpreted directly by the shell (for shells like bash, csh, tcsh, etc,). It thus works in a non-standard way and it times the whole rest of the command-line (unless you are using a very unusual shell).

So, to get the result you want (using bash), you need to use:

(time ls) 2>&1 | grep real

This will run the "ls" in a subshell and time it [ (time ls) ] , send standard error to standard out [ 2>&1 ] , and then send standard out to "grep" [ |grep ].

The last part that you used ">?dev/null" throws away the normal output from the ls command itself, in case that included the word "real."


It appears that time writes direct to the console and not to stdout, which means that the output from the command or pipeline is not affected by adding time.

So grep never sees the time report, which in any case is generated after grep completes, since the whole pipeline is timed.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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