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.

  • 1
    it's easy: always quote variables – Ipor Sircer Dec 29 '16 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. – terdon Dec 29 '16 at 15:02
  • If $var is empty, I need to call "java ... param1 param2 param4". $var is not an argument to param2. – ARX Dec 29 '16 at 15:09
  • This question has an answer here. – G-Man Feb 21 '17 at 23:16
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

  • 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 – xhienne Dec 29 '16 at 15:37
  • And indeed, this is exactly what I needed. Works seamlessly. Thanks a lot! – ARX Dec 29 '16 at 15:53
4

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.

  • 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. – ARX Dec 29 '16 at 16:30
  • @phk good to know... nice answer. – George Vasiliou Dec 29 '16 at 19:41
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 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.