2

Usually, the time command outputs three lines:

> time sleep 2
real    0m2.003s
user    0m0.000s
sys     0m0.006s

However, when prepended with variable assignment, the output becomes one line:

> VAR="" time sleep 2
0.00user 0.00system 0:02.00elapsed 0%CPU (0avgtext+0avgdata 2060maxresident)k
0inputs+0outputs (0major+86minor)pagefaults 0swaps

Why is this happening? And is there a way to keep variable assignment while having the output in three lines?

justhalf
  • 174
  • 1
  • 9

2 Answers2

4

Why is this happening?

In Bash time is a reserved word (keyword) that can precede and measure not only a simple command; it can measure a pipeline. As such, it must be the first word. This syntax only informs Bash that you want to measure time; the rest of the pipeline is still processed by Bash as if time wasn't there.

If time is not the first word and still can be interpreted as a command, it's interpreted as a regular external command (not even a builtin), looked up in $PATH and executed; e.g. it can be /usr/bin/time. This tool processes its arguments and builds the actual command from them.

The two utilities produce output in different formats.


And is there a way to keep variable assignment while having the output in three lines?

Yes. You can use time as the first word, so it gets interpreted as the keyword:

time VAR="" sleep 2

Note both implementations support -p that changes the output format to that specified by POSIX (in fact the support for -p itself is required by POSIX). This means the following two commands will produce output in the same format:

time -p VAR="" sleep 2
VAR="" time -p sleep 2

Under the hood, however, these are very different.

Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202
0

Time sends its output to STDERR and not STDOUT.

There are a couple of options though I'm not clear on how you plan to use the captured data so I'll lay it out in three lines.

$ narf="$( ( time sleep 2 ) 2>&1 )" ; echo "${narf}" ; unset narf  

real    0m2.002s
user    0m0.001s
sys 0m0.001s

$ narf="$( ( time sleep 5 ) 2>&1 )" ; echo "${narf}" ; unset narf  

real    0m5.002s
user    0m0.001s
sys 0m0.001s

$ narf="$( ( time -p sleep 5 ) 2>&1 )" ; echo "${narf}" ; unset narf  
real 5.00
user 0.00
sys 0.00

The first two options do not use the -p formatting option (which is designed for POSIX compliance). The third option does.

As you can see the output varies somewhat. Ask me questions if you'd like. (You can drop the unset command as I was using that to perform multiple tests.)

JamesIsIn
  • 61
  • 5
  • 2
    Thanks for your answer! I'm not sure how this answers my question, though. – justhalf Nov 27 '19 at 06:57
  • I was writing a comment to tell you you should really concentrate on answering explicit questions instead of assuming the OP wants to process the output, anticipating and solving possible problems basing on this assumption. By deleting your previous answer you made me type the comment again. This is all you achieved because I can dowvote this one as well. I won't. I was truly going to revoke my downvote because your code (yet cumbersome) makes some sense now. Your answer still doesn't answer the question. – Kamil Maciorowski Nov 27 '19 at 06:58
  • I suppose you could downvote it. If you had not on the first I wouldn't have re-posted. I was able to fix both your concerns. How a command gets used is often driven by why it is used. Context is everything in writing a single line of code. A solution may be good or bad depending utterly on the context. I see no reason to repeat what you have already said in your answer. Hence my answer doesn't. And I've endeavored to ensure my answer is true, relevant, and useful. (In all three variable assignments in your answer $VAR is empty.) – JamesIsIn Nov 27 '19 at 07:06
  • (1) `$VAR` is empty because the OP wanted it so. It makes no difference whatsoever; the act of assignment matters, empty or not. (2) If another answer fully answers the question and all you can do (besides repeating) is provide potentially useful hint/code/whatever that *does not* answer the question, you should not post this as an answer. (3) When I said "this is all you achieved" I was mistaken. Please see [this post](https://meta.stackexchange.com/a/86998/355310) where it says "Are deleted posts taken into account too?" – Kamil Maciorowski Nov 27 '19 at 07:16
  • What an odd question then. I mean ```VAR="" ; time sleep 2``` would answer the question as to how to prevent the line conglomerating. Does your answer explain why the output differs between time and /usr/bin/time? ```which time``` gives /usr/bin/time as you suggest and if I try ```VAR="" ; /usr/bin/time sleep 2``` I get similar output to the OP but dissimilar to ```VAR="" ; time sleep 2```. @KamilMaciorowski – JamesIsIn Nov 27 '19 at 11:41
  • 1
    The question is not odd. `VAR="" ; time sleep 2` affects `VAR` in the current shell and does not affect `VAR` seen by `sleep` (unless `VAR` is exported). The OP wants the opposite: not to affect `VAR` in the current shell and to set it empty (yet existing) for `sleep`. The output differs between `time` and `/usr/bin/time` because these are different implementations. In `VAR="" ; time sleep 2` you have two (trivial, degenerate) pipelines and `time` is the first word of the second one, so it's the keyword. – Kamil Maciorowski Nov 27 '19 at 12:19
  • Sorry for my continued slowness. Is the difference in output between ```time date``` and ```/usr/bin/time date``` due to the peculiarity that /usr/bin/time runs the command time and does not evoke the keyword time (in spite of what ```which time``` tells us? @KamilMaciorowski – JamesIsIn Nov 27 '19 at 12:48
  • Also, I found this which is loaded with related resource (for those reading along): https://unix.stackexchange.com/questions/267761/differences-between-keyword-reserved-word-and-builtin – JamesIsIn Nov 27 '19 at 12:50
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/101552/discussion-between-kamil-maciorowski-and-jamesisin). – Kamil Maciorowski Nov 27 '19 at 12:52
  • 2
    I used the link you provided to improve my answer. Thank you. – Kamil Maciorowski Nov 27 '19 at 13:32
  • 1
    @JamesIsIn Thanks for your effort! (and Kamil for participating here as well). To clarify a few things, my purpose of wanting the three-line output is because it is easier to read. And about the empty assignment to `VAR`, Kamil got it correct, I just want the assignment to affect only the command I am running. Finally, thanks Jameslsln for the link to the resource! That's helpful. – justhalf Nov 28 '19 at 03:09
  • Glad to be of service. Turns out this is a pretty complex arena of bash. – JamesIsIn Nov 28 '19 at 06:03