10

I have a long command which I want to modify in a certain case to either include an option or not.

E.g.

java -jar compiler.jar --externs "$externs" --foo "another" --bar "more" 

where I want the --externs "$externs" to be omitted completely if $externs is empty. Is there any way to do this in bash without resorting to building up the whole command with a string?

7
  • I assume this is within the context of a script? Commented Dec 7, 2015 at 22:43
  • Yes, it's within a larger script. One other possibility that I'm trying to avoid is simply repeating the command in two if branches. That gets hairy if there are a few different commands which need to be omitted. I was thinking there might be some string substitution command that resulted in bash not even inserting the argument. But I haven't found it yet, if it exists. Commented Dec 7, 2015 at 22:44
  • how about this: stackoverflow.com/questions/14763608/… Commented Dec 7, 2015 at 22:46
  • Incidentally, this is subquestion 3 of BashFAQ #50: mywiki.wooledge.org/BashFAQ/… Commented Dec 7, 2015 at 22:54
  • 1
    @miken32, you deleted your answer before I could answer your request for clarification. Inspect the output of externs='two words'; if [ ! -z "$externs" ]; then externs_option="--externs \"$externs\""; fi; printf '%q\n' java -jar compiler.jar $externs_option --foo "two words" --bar "etc" -- and compare the two words passed alongside --externs and that passed alongside --foo. Commented Dec 7, 2015 at 23:02

2 Answers 2

12

This is what the ${key:+WORDS} expansion is for:

java ... ${externs:+--externs "$externs"} 

It's also a common idiom to use an array for the purpose:

args=( ) if [[ $externs ]]; then args+=( --externs "$externs" ) fi java ... "${args[@]}" 
Sign up to request clarification or add additional context in comments.

4 Comments

This answer is well-written and I like your array approach as well. I think you're missing a : before the + though.
@ChrisMiddleton, whether one wants a : before the + depends on how you want to handle empty, as opposed to unset, values; if you want to treat a variable that exists but is empty as if it were unset, then yes, it would be :+.
@ChrisMiddleton, ...rereading your question, you did indeed explicitly say "empty"; edited appropriately.
Using Google's Closure Compiler, I have to provide each extern file with a separate "--externs" option, so your array approach has become very useful in my case.
5

You could try

java -jar compiler.jar ${externs:+--externs} "${externs:-}" --foo "another" --bar "more" 

explanation, from bash docs

${parameter:-word}

Use Default Values. If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

${parameter:+word}

Use Alternate Value. If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

You could try it yourself with:

externs="some value" printf '%s\n' ${externs:+--externs} "${externs:-}" 

output

--externs
some value

Note: I used printf here test the case of $externs containing multiple words, where if the quoting wasn't being applied after the variable expansion, the output would look like

--externs
some
value

So I believe that should suffice.

externs= echo ${externs:+--externs} "${externs:-}" 

output: nil

3 Comments

From a correctness perspective, I have nothing to add to this -- it's a good answer (and a little more paranoid about hewing to the POSIX sh specification than mine, which relies on behavior that bash implements but doesn't document terribly well). That said -- what's up with the formatting? > principally used to indicate that one is quoting text; presumably it has a different meaning here.
Thanks for your answer. I especially like the use of :-. I chose Charles's only because it was first and had the array solution as well, but there's some neat stuff here. From some experimenting, I see that if foo=, then ${foo:-} will be an omitted parameter whereas ${foo:-""} will be the empty string. Cool.
cool , me the > format just helps to visually distinguish between code and output. Of course its always helpful if your code is portable

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.