Discussion:
[Help-bash] Why time does not take environment variable?
Peng Yu
2018-11-26 19:31:43 UTC
Permalink
Hi,

I thought that the first TIMEFORMAT set the environment variable for
`time` temporarily. But it apparently has no effect. Could anyone help
me understand why it is so? Thanks.

TIMEFORMAT=%3R time sleep 1
1.00 real 0.00 user 0.00 sys
export TIMEFORMAT=%3R
time sleep 1
1.018
--
Regards,
Peng
Greg Wooledge
2018-11-26 19:38:11 UTC
Permalink
Post by Peng Yu
Hi,
I thought that the first TIMEFORMAT set the environment variable for
`time` temporarily. But it apparently has no effect. Could anyone help
me understand why it is so? Thanks.
TIMEFORMAT=%3R time sleep 1
1.00 real 0.00 user 0.00 sys
export TIMEFORMAT=%3R
time sleep 1
1.018
Because there are TWO different time commands: one is external (probably
in /usr/bin/) and the other is a special bash keyword, which is like
a builtin with extra voodoo powers.

If you just run "time mycmd", you are using bash's keyword. But if you
stick a variable assignment in front of it, then you are using the
external one.

wooledg:~$ time sleep 0.1
real 0.102 user 0.004 sys 0.000

wooledg:~$ x=y time sleep 0.1
0.00user 0.00system 0:00.10elapsed 0%CPU (0avgtext+0avgdata 1836maxresident)k
16inputs+0outputs (1major+72minor)pagefaults 0swaps
Bob Proulx
2018-11-26 19:56:44 UTC
Permalink
Post by Peng Yu
I thought that the first TIMEFORMAT set the environment variable for
`time` temporarily. But it apparently has no effect. Could anyone help
me understand why it is so? Thanks.
TIMEFORMAT=%3R time sleep 1
1.00 real 0.00 user 0.00 sys
export TIMEFORMAT=%3R
time sleep 1
1.018
Inside bash 'time' is a shell keyword. Outside of bash 'time' is a
standalone utility.

$ type -a time
time is a shell keyword
time is /usr/bin/time

Why two? Because in bash 'time' will time the full command pipeline.
An external command cannot do that and would only be able to time one
command at a time. One would need to construct a time sh -c 'A | B'
type of thing in order to have the external 'time' work on a single
command line command. That is why 'time' is a shell keyword. It
needs to be special in order to time a pipeline of commands.

Therefore the shell syntax to set a variable for just one command
cannot be used before 'time' to set it. Doing so causes it to invoke
the external command.

You can always use the external GNU time command.

$ env TIME=%e time sleep 2.35
2.35

Bob
Peng Yu
2018-11-26 20:18:31 UTC
Permalink
Post by Bob Proulx
Post by Peng Yu
I thought that the first TIMEFORMAT set the environment variable for
`time` temporarily. But it apparently has no effect. Could anyone help
me understand why it is so? Thanks.
TIMEFORMAT=%3R time sleep 1
1.00 real 0.00 user 0.00 sys
export TIMEFORMAT=%3R
time sleep 1
1.018
Inside bash 'time' is a shell keyword. Outside of bash 'time' is a
standalone utility.
$ type -a time
time is a shell keyword
time is /usr/bin/time
Why two? Because in bash 'time' will time the full command pipeline.
An external command cannot do that and would only be able to time one
command at a time. One would need to construct a time sh -c 'A | B'
type of thing in order to have the external 'time' work on a single
command line command. That is why 'time' is a shell keyword. It
needs to be special in order to time a pipeline of commands.
Therefore the shell syntax to set a variable for just one command
cannot be used before 'time' to set it. Doing so causes it to invoke
the external command.
You can always use the external GNU time command.
$ env TIME=%e time sleep 2.35
2.35
It seems that `time` is special in the aspect of whether an inline
environment variable can be set or not. Is it documented somewhere in
the manual? Thanks.

$ cat help
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

declare -p BASH_SOURCE
$ cat time
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

declare -p BASH_SOURCE
$ cat ./main.sh
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

set -v
X=10 help | head -n 1
TIMEFORMAT=%R time sleep 1

export PATH=".:$PATH"
X=10 help | head -n 1
TIMEFORMAT=%R time sleep 1
$ ./main.sh
X=10 help | head -n 1
GNU bash, version 4.4.19(1)-release (x86_64-apple-darwin17.3.0)
TIMEFORMAT=%R time sleep 1
1.01 real 0.00 user 0.00 sys

export PATH=".:$PATH"
X=10 help | head -n 1
GNU bash, version 4.4.19(1)-release (x86_64-apple-darwin17.3.0)
TIMEFORMAT=%R time sleep 1
declare -a BASH_SOURCE=([0]="./time")
--
Regards,
Peng
Chet Ramey
2018-11-26 22:25:20 UTC
Permalink
Post by Peng Yu
It seems that `time` is special in the aspect of whether an inline
environment variable can be set or not. Is it documented somewhere in
the manual? Thanks.
You're looking at it the wrong way.

The bash manual documents `time' as a reserved word. Reserved words are not
documented as being able to be prefixed with assignment statements -- they
are not recognized as reserved words unless they are the first word in a
simple command. If they have to be the first word, there can be no words,
like assignment statements, preceding them.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Peng Yu
2018-11-26 23:15:21 UTC
Permalink
Post by Chet Ramey
Post by Peng Yu
It seems that `time` is special in the aspect of whether an inline
environment variable can be set or not. Is it documented somewhere in
the manual? Thanks.
You're looking at it the wrong way.
The bash manual documents `time' as a reserved word. Reserved words are not
documented as being able to be prefixed with assignment statements -- they
are not recognized as reserved words unless they are the first word in a
simple command. If they have to be the first word, there can be no words,
like assignment statements, preceding them.
OK. I see. `time` is different from other commands (like `help`) in
the sense that it can recognize things like "|".

[time [-p]] [ ! ] command [ [|||&] command2 ... ]

I can see that environment variables cannot be set for other reserved
words, like `while`.

$ TIMEFORMAT=%R while true; do time sleep 1; break; done
-bash: syntax error near unexpected token `do'

However, had bash allowed such syntax, would it causes any conflict to
other bash language syntaxes. If it would not, why not allow setting
environment variables before reserved words? Thanks.
--
Regards,
Peng
Chet Ramey
2018-11-26 23:24:39 UTC
Permalink
Post by Peng Yu
However, had bash allowed such syntax, would it causes any conflict to
other bash language syntaxes. If it would not, why not allow setting
environment variables before reserved words? Thanks.
Because that's the thing that differentiates recognizing a reserved word
from any other word. Reserved words are only reserved at specific places
in the grammar, including as the first word of a command.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://tiswww.cwru.edu/~chet/
Loading...