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.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
ARX
  • 447
  • 1
  • 4
  • 15
  • 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](//unix.stackexchange.com/q/171346/80216/#286350). – G-Man Says 'Reinstate Monica' Feb 21 '17 at 23:16

3 Answers3

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

xhienne
  • 17,075
  • 2
  • 52
  • 68
iruvar
  • 16,515
  • 8
  • 49
  • 81
  • 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
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.

phk
  • 5,893
  • 7
  • 41
  • 70
  • 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. – ARX Dec 29 '16 at 16:30
  • @phk good to know... nice answer. – George Vasiliou Dec 29 '16 at 19:41
  • after many attempts and google searches, I´ve had to use this `${VAR[@]}` thing that I don't understand - thanks! – carnicer Feb 05 '21 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 
George Vasiliou
  • 7,803
  • 3
  • 18
  • 42