Reputation: 79
I was writing a small shell script in bash to measure the speed of several executables using the time
command. Because I wanted to time several different programs, to avoid repeating myself I saved the time command and the format string I wanted and tried to use variable expansion (testing the performance of ls
as an example):
#!/usr/bin/env bash
timer="/usr/bin/time -f 'elapsed time: %E' --"
$timer ls 1>/dev/null
The time
command is supposed to use the --
to separate its options (in this case a format string) from the command it's supposed to time. However, in this script time
insists on trying to execute my format string and fails with
/usr/bin/time cannot run time:: No such file or directory
Command exited with non-zero status 127
'elapsed
But if I put the whole command on one line with no variable expansion it correctly recognizes the format string and executes ls
:
#!/usr/bin/env bash
/usr/bin/time -f 'elapsed time: %E' -- ls 1>/dev/null
produces "elapsed time: 0:00.00"
I ended up just typing out the whole command on each line to get it to run, but I was curious if anyone could explain why variable expansion doesn't work here.
Upvotes: 0
Views: 90
Reputation: 123450
The data in $timer
is split on $IFS
(spaces), and used as separate arguments. It is not expanded and then evaluated as bash code.
Your command $timer ls
is therefore equivalent to:
"/usr/bin/time" "-f" "'elapsed time:" "%E'" "--" "ls"
The correct way to do this in your case is using a function:
timer() {
/usr/bin/time -f 'elapsed time: %E' -- "$@"
}
timer ls
PS: This problem is automatically pointed out by shellcheck.
Upvotes: 2
Reputation: 785058
You need to use a BASH array to store command line:
timer=(/usr/bin/time -f 'elapsed time: %E' --)
"${timer[@]}" ls
Upvotes: 1