Bash time keyword result only with second piped command, explain why

bashtime

I have a bash time keyword command which I cannot fully explain, but it works for me.

My Goal:

  1. to find the execution time of some python script, which takes a variable btw, from within a bash script, and capture that value.

  2. also to capture the output of the python script in the same variable, for success or failure analysis.

After reading around I ended up with this command, but I am not fully able to explain it.

ttime=$( (TIMEFORMAT="%U^"; time  /../myscript.py ${__myvar} 2>&1 )|& tr -d f)

Can you explain why I need the second command tr -d f in the pipe, for the time value to be appended to the output of the command,

The choice of 'tr -d f' was entirely arbitrary, and will not affect my script's output, std or err, but without it, or another command which acts on the scripts text output in some minor way, I see the return from the python without the time appended, why?

Edit:

The real question should have been why is the |& tr -d f . needed, and as Stephanie says it is the |& which is allowing the timings found in the sterr from the time keyword to be passed into the pipeline output

Solution now looks like:

ttime=$(TIMEFORMAT="%U^"; { time /../myscript.py ${__myvar} ; } 2>&1 )

Field Descriptor Tutorial:

http://wiki.bash-hackers.org/howto/redirection_tutorial

Best Answer

In bash, like in ksh, time is a keyword (not builtin) that is used to time a pipeline (not only simple command, it can also time compound commands).

In time cmd 2> something, we're timing cmd 2> something and printing the output to stderr, but to the original stderr.

You need stderr redirected before the time construct is invoked. Which you do with your |& that redirects the stdout and stderr of the subshell time is run in, but a much simpler way to do it would be:

time=$(TIMEFORMAT="%U^"; { time cmd; } 2>&1)

That doesn't involve a subshell (here we use a command group instead) nor an extra command.

Note that with bash:

time=$(time (cmd) 2>&1)

happens to work by accident. I wouldn't rely on that as it might change in future versions and doesn't work in other shells that have a time keyword.

If you wanted only the timing output in $time (and not the command's stdout or stderr), you'd do:

{ time=$(TIMEFORMAT="%U^"; { time cmd 2>&3 3>&-; } 2>&1); } 3>&1
Related Question