Jonathan Abrahams
Jonathan Abrahams

Reputation: 409

Build a shell command in a string for later execution portably

I am trying to do the following command in bash and dash:

x="env PATH=\"$PATH:/dir with space\""
cmd="ls"
"$x" $cmd

This fails with

-bash: env PATH="/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/git/bin:/usr/local/go/bin:/dir with space": No such file or directory

Note the following works:

env PATH="$PATH:/dir with space" $cmd

The reason I am assigning to variable x env, is because it is part of a larger command wrapper to $cmd, which is also a complicated variable.

It's more complex than the initial example. I have logic in setting these variables,, instead of repeating them each time. Eventually the invocation is as shown here:

path_value="$PATH"
invocation="env PATH=\"$path_value\" $other_val1 $other_val2"
base="python python_script.py --opt1=a,b,c script_args"
add_on="$base more_arg1 more_arg2"
"$invocation" $base

Upvotes: 1

Views: 64

Answers (2)

mklement0
mklement0

Reputation: 437478

anubhava's helpful array-based bash answer is the best choice if you can assume only bash (which appeared to be the case initially).

Given that you must also support dash, which almost exclusively supports POSIX sh features only, arrays are not an option.

Assuming that you fully control or trust the values that you use to build your command line in a string, you can use eval, which should generally be avoided:

path_value="$PATH"
invocation="env PATH=\"$path_value\" $other_val1 $other_val2"
base="python python_script.py --opt1=a,b,c script_args"
add_on="$base more_arg1 more_arg2"

eval "$invocation $add_on"

Upvotes: 0

anubhava
anubhava

Reputation: 785098

You can use shell array to store and reuse:

x=(env PATH="$PATH:/dir with space")
cmd="ls"
"${x[@]}" "$cmd"

Upvotes: 1

Related Questions