2

I feel really reluctant to ask this question as it feels like I must be missing something really obvious. However, I am unable to find existing questions with exactly the same problem.

We have a script that we should not edit, and it is causing a problem in how it is handling arguments that include whitespace. I have reduced the problem to a very simple reproducible case:

First, I created a simple script that just outputs the commandline arguments passed to it:

#!/bin/bash
for i; do
    echo $i
done

Then I define an environment variable that will be passed into the commandline

MYOPT="With Space"

Then, and this is the part I am unable to change in our environment, I call the command using the variable as a parameter. Unfortunately, the variable is not quoted in our environment.

./mycommand.sh $MYOPT

The output of this is, as you would expect,

./mycommand.sh $MYOPT
"With
Space"

If you do quote the variable in the above command, it works. This seems to be the generally accepted solution to this problem when looking around at other similar questions.

./mycommand.sh "$MYOPT"
"With Space"

However, as I mentioned, we are unable to change how this script is called.

I tried adding in extra quotes in the environment variable as follows, but this too did not help:

MYOPT="\"With Space\""
./mycommand.sh $MYOPT
"With
Space"

Is there a way of defining this environment variable with spaces such that it can be passed into a script without quoting it in the invocation?

For those who are interested, this problem is presenting itself in our RHEL7 tomcat environment. JAVA_OPTS is set in tomcat.conf and we have -Dparamaters="with spaces". The main control script that comes with Tomcat does not quote these JAVA_OPTS when it calls Java, which leads to this problem. I reduced the problem to the simple example above.

Wildcard
  • 36,499
Tom17
  • 281

1 Answers1

2

You cannot go back from ./mycommand.sh $MYOPT to the value of MYOPT. That's why you didn't find a way to do it: it's impossible. mycommand.sh does not receive enough information to reconstruct the original value.

For example, if the value of MYOPT is * then mycommand.sh is called with the list of file names in the current directory. It has no way to know how this list was constructed.

If you know that the value of MYOPT follows certain rules then you may be able to reconstruct it. The simple version of these rules is:

  • The value doesn't contain any of the characters \[*? or tab or newline.
  • The value does not start or end with a space and does not contain consecutive spaces.

Under these assumptions, "$*" in mycommand.sh will give you the value of MYOPT. But keep in mind that this cannot work in general.

The proper solution is to fix your environment. In the shell language, $MYOPT does not mean “take the value of MYOPT”, it means “take the value of MYOPT, split it according to the value of IFS, and treat each resulting part as a wildcard pattern which is expanded if it matches at least one file”. The way to write “take the value of MYOPT” is "$MYOPT", or more generally to use $MYOPT inside double quotes.

  • Gilles, what about using printf -v MYOPT '%q' "With Space" to shell-quote MYOPT, is that a viable option? – iruvar May 10 '17 at 13:59
  • @iruvar It sets the variable MYOPT to a form that can be parsed with eval. That's useful sometimes, but not here: if you have control over the caller to make it do that, change the caller to quote $MYOPT. – Gilles 'SO- stop being evil' May 10 '17 at 20:16