4

I would like to call a tool via command line. I need to generate the parameters to be used for calling dynamically. Furthermore there is a number of parameters which needs to be given to the tool.

COMMAND=""
for i in $VERSIONS; do
    COMMAND+=" '../apache-maven-$i/bin/mvn clean'"
done

So now I want to call the tool with the generated list of parameters (from above) like this:

hyperfine --export-markdown ../results.md -w 5 $COMMAND

But unfortunately that produces the following result:

Benchmark #1: '../apache-maven-3.0.5/bin/mvn
Error: Command terminated with non-zero exit code. Use the '-i'/'--ignore-failure'
     option if you want to ignore this. Alternatively, 
use the '--show-output' option to debug what went wrong.

My assumption is that the created parameters $COMMAND is not identified as multiple parameters. It's taken as a single parameter which is wrong. If I printout the whole command line and copy that into the bash line manually the execution works perfectly.

hyperfine --export-markdown ../results.md -w 5 '~/tools/apache-maven-3.8.2/bin/mvn clean' '~/tools/apache-maven-3.8.1/bin/mvn clean' '~/tools/apache-maven-4.0.0-alpha-1-SNAPSHOT/bin/mvn clean'

Is there something special to be taken into account while generating multiple parameters for calling other tools in Bash?

ilkkachu
  • 138,973

1 Answers1

6

Your issue here is that the single quotes are becoming part of the commands you want to benchmark with hyperfine.

Instead, we suppose you want to collect all the commands in an array and then use that.

commands=()
for version in "${versions[@]}"; do
    commands+=( "../apache-maven-$version/bin/mvn clean" )
done

hyperfine --warmup 5 --export-markdown ../results.md "${commands[@]}"

In the code above, I'm assuming that versions is an array, like

versions=( '3.8.1' '3.8.2' '4.0.0-alpha-1-SNAPSHOT' )

The expansion of "${commands[@]}" will be the commands that you want to benchmark, each individually quoted.

However, hyperfine can use your versions array directly.

(
        IFS=,
        hyperfine               \
                --warmup 5      \
                --export-markdown ../results.md                 \
                --parameter-list version "${versions[*]}"       \
                '../apache-maven-{version}/bin/mvn clean'
)

or, if you prefer short options and long one-liners,

( IFS=, ; hyperfine -w 5 --export-markdown ../results.md -L version "${versions[*]}" '../apache-maven-{version}/bin/mvn clean' )

Again, this assumes that versions is an array like what we showed above. Setting IFS to a comma makes "${versions[*]}" expand to a comma-delimited string of version strings. Doing this in a subshell avoids modifying IFS in the calling shell.

When you use a comma-delimited string with --parameter-list placeholder, any occurrence of the string {placeholder} in the command string given as the operand is replaced by the elements of that string in turn.

Kusalananda
  • 333,661