6

I need to pass as a program argument a parameter expansion. The expansion results in a filename with spaces. Therefore, I double-quote it to have the filename as a single word: "$var".

As long as $var contains a filename, the program gets a single-word argument and it works fine. However, at times the expansion results in an empty string, which when passed as argument, breaks the program (which I cannot change).

Not removing the empty string is the specified behavior, according to Bash Reference Manual:

If a parameter with no value is expanded within double quotes, a null argument results and is retained.

But then, how do I manage the case where I need to quote variables, but also need to discard an empty string expansion?

EDIT:

Thanks to George Vasiliou, I see that a detail is missing in my question (just tried to keep it short :) ). Running the program is a long java call, which abbreviated looks like this:

java -cp /etc/etc MyClass param1 param2 "$var" param4

Indeed, using an if statement like that described by George would solve the problem. But it would require one call with "$var" in the then clause and another without "$var" in the else clause.

To avoid the repetition, I wanted to see if there is a way to use a single call that discards the expansion of "$var" when it is empty.

4
  • 1
    it's easy: always quote variables Commented Dec 29, 2016 at 14:27
  • 1
    Sorry, but it is still not clear. What should be passed to the command if $var is empty? Is $var an argument to param2 so we also need to remove param2? Or do you just want to run java . . . param1 param2 param4? Unless $var is an argument to an option, I don't see how having it there could make any difference if it is empty. Commented Dec 29, 2016 at 15:02
  • If $var is empty, I need to call "java ... param1 param2 param4". $var is not an argument to param2. Commented Dec 29, 2016 at 15:09
  • This question has an answer here. Commented Feb 21, 2017 at 23:16

3 Answers 3

7

The ${parameter:+word} parameter expansion form seems to do the job

( xyz=2; set -- ${xyz:+"$xyz"}; echo $# )
1

( xyz=; set -- ${xyz:+"$xyz"}; echo $# )
0

( unset xyz; set -- ${xyz:+"$xyz"}; echo $# )
0

So that should translate to

program ${var:+"$var"}

in your case

2
  • IMHO, this is exactly what the OP is expecting. I have edited the answer to change ${var+...} to ${var:+...} because it is clear from the OP that no substitution must occur if variable is set but empty Commented Dec 29, 2016 at 15:37
  • And indeed, this is exactly what I needed. Works seamlessly. Thanks a lot! Commented Dec 29, 2016 at 15:53
5

In bash and shells with similar array support you can do the following:

# default is an empty array
param=()

# if $var is not empty then add it to array
[[ "$var" ]] && param=("$var")

# use the $@-like magic for arrays
java -cp /etc/etc MyClass param1 param2 "${param[@]}" param4

Demo

demo() {
  [[ "$var" ]] && param=("$var") || param=()

  echo -n 'output: '
  printf '<%s> ' before "${param[@]}" after
  echo
}

demo # output: <before> <after> 

var=''
demo # output: <before> <after> 

var='foo bar'
demo # output: <before> <foo bar> <after> 

Note

See also https://github.com/koalaman/shellcheck/wiki/SC2086#exceptions where the approach from iruvar's answer is also explained again.

3
  • 1
    This is a great addition to iruvar's answer. For calls with many similar arguments, they can be placed in the array, and expanded from it, in the way you explain. Commented Dec 29, 2016 at 16:30
  • @phk good to know... nice answer. Commented Dec 29, 2016 at 19:41
  • after many attempts and google searches, I´ve had to use this ${VAR[@]} thing that I don't understand - thanks! Commented Feb 5, 2021 at 20:32
3

Is not clear what you are trying to do, but isn't a simple if enough? For example:

[[ ! -z "$var" ]] && call_program_with_arg "$var" 

Or

if [[ ! -z "$var" ]];then call_program "$var";fi

If $var is empty then nothing hapens. If is not empty then call the program you want.

After Question Update:

parameters=( "Param1" "Param2" )
[[ ! -z "$var" ]] && parameters+=( "$var" "Param4") || parameters+=( "Param4" )
java -cp /etc/etc MyClass "${parameters[@]}"

Testing:

$parameters=( "Param1" "Param2" );var="my file.java";[[ ! -z "$var" ]] && parameters+=( "$var" "Param4") || parameters+=( "Param4" );echo java -cp /etc/etc MyClass "${parameters[@]}"                                                                                                              
>java -cp /etc/etc MyClass Param1 Param2 my file.java Param4
$parameters=( "Param1" "Param2" );var="";[[ ! -z "$var" ]] && parameters+=( "$var" "Param4") || parameters+=( "Param4" );echo java -cp /etc/etc MyClass "${parameters[@]}"                                                                                                               
>java -cp /etc/etc MyClass Param1 Param2 Param4 
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.