1

I do have 2 Shell Scripts. The first one triggers the second one and adds some parameters. The second one calls a command and adds the parameters from the first script as parameters for the command.

The first looks something like:

#!/usr/bin/env bash

ADDITIONAL_ARGUMENTS='--set "args={/bin/bash,-c,cd /var/www && sudo -u www-data bash scripts/system/update.sh}"'

SUPER_PARAMS=${ADDITIONAL_ARGUMENTS} my_second_script.sh

Then, the second script does something like:

#!/usr/bin/env bash

randomBinary --some-hardcoded-parameters \
             "${SUPER_PARAMS}"

What I would expect to have is an output of:

randomBinary --some-hardcoded-parameters --set "args={/bin/bash,-c,cd /var/www && sudo -u www-data bash scripts/system/update.sh}"

But instead, the call looks like:

randomBinary --some-hardcoded-parameters '--set "args={/bin/bash,-c,cd /var/www && sudo -u www-data bash scripts/system/update.sh}"'

I tried 2 days quoting the param correctly, but no results.

0

2 Answers 2

3

To store several arguments, use an array, not a scalar variable.

additional_arguments=(
  --set
  'args={/bin/bash,-c,cd /var/www && sudo -u www-data bash scripts/system/update.sh}'
)
randomBinary --some-hardcoded-parameters "${additional_arguments[@]}"

Note that since environment variables are strings of non-NUL bytes, you need some encoding if you want to pass an array definition to another command via the environment.

With ksh, bash, zsh or yash you can use:

ARRAY_DEFINITION="$(typeset -p additional_arguments)" my_second_script.sh

to export the array definition in an environment variable in the calling script.

And eval "$ARRAY_DEFINITION" in the called script to import that array definition.

Note that it's important the code is evaluated in the same locale and with the same shell as the one in which it was generated.

Also note that if the array definition is evaluated inside a function, the array will be local to the function.

Some shells like rc, es or fish allow exporting arrays (using their own encoding internally).

Here, it would be easier to pass the information as arguments to the called script, as that's one array.

In the calling script:

my_second_script.sh "${additional_arguments[@]}"

In the called script:

randomBinary --some-hardcoded-parameters "$@"

Or call the called script with . so it shares the shell variables of the caller so you don't need to use the environment to pass that data across an execution.

0

Here,

randomBinary --some-hardcoded-parameters "${SUPER_PARAMS}"

SUPER_PARAMS contains --set "args={/bin/bash,-c,cd /var/www && sudo -u www-data bash scripts/system/update.sh}", and since it's quoted, it's passed as-is. If it was unquoted, it would be split on whitespace to the five strings --set,"args={/bin/bash,-c,cd, /var/www, &&, sudo -u www-data bash scripts/system/update.sh}", and those would be passed as arguments.

It seems you want to have the quotes inside the variable also be interpreted, and that requires adding another layer of shell parsing, with either eval or running the thing through bash -c '...'

The test script here:

$ cat test.sh
#!/bin/bash    
ARGS='--set "args={this, that && that}"'
./args.sh $ARGS
eval "./args.sh $ARGS"

prints:

<!-- language: lang-none -->
$ bash test.sh
5 args: <--set> <"args={this,> <that> <&&> <that}"> 
2 args: <--set> <args={this, that && that}> 

(The script args.sh prints the number is the number of distinct arguments, and the arguments itself are printed within <...>)

Note that the eval will execute e.g. any command substitutions, so it opens arbitrary code execution. Usually, it would be better to hold the arguments in a shell array instead, but here you're passing them from one script to another, so that doesn't work too well. See the section "How do I store a command in a variable?" in this answer about dealing with whitespace.

Also Word Splitting in the Bash Guide, and you could also use set -x to see what commands the shell actually runs.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .