Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass shell-escaped string of arguments to a subcommand in Bourne shell

Say I have a command I want to run (cmd) and a variable containing the arguments I want to pass to the function (something like --foo 'bar baz' qux). Like so:

#!/bin/sh
command=cmd
args="--foo 'bar baz' qux"

The arguments contain quotes, like the ones shown above, that group together an argument containing a space. I'd then like to run the command:

$command $args

This, of course, results in running the command with four arguments: --foo, 'bar, baz', and qux. The alternative I'm used to (i.e., when using "$@") presents a different problem:

$command "$args"

This executes the command with one argument: --foo 'bar baz' qux.

How can I run the command with three arguments (--foo, bar baz, and qux) as intended?

like image 854
adrian Avatar asked Dec 01 '22 23:12

adrian


2 Answers

Use an array to specify your argument list exactly, without string-splitting (which is what's doing the wrong thing here) getting in your way:

args=( --foo "bar baz" qux )
command "${args[@]}"

If you need to build your argument list dynamically, you can append to arrays with +=:

args=( )
while ...; do
   args+=( "$another_argument" )
done
call_your_subprocess "${args[@]}"

Note that the use of quotation marks, and [@] instead of [*], is essential.

like image 123
Charles Duffy Avatar answered Dec 29 '22 05:12

Charles Duffy


If you can throw away the current positional variables ($1...) you can use the following:

set -- '--foo' 'bar baz' 'qux'
echo "$#" # Prints "3" (without quotes)
echo "$2" # Prints "bar baz" (without quotes)
command "$@"

Just tested it in a #!/usr/bin/env sh script, so it works at least in Dash, and should work in any Bourne Shell variant. No eval, Python or Bash necessary.

like image 44
l0b0 Avatar answered Dec 29 '22 06:12

l0b0