11

Possible Duplicate:
Ternary operator (?:) in Bash

If this were AS3 or Java, I would do the following:

fileName = dirName + "/" + (useDefault ? defaultName : customName) + ".txt";

But in shell, that seems needlessly complicated, requiring several lines of code, as well as quite a bit of repeated code.

if [ $useDefault ]; then
    fileName="$dirName/$defaultName.txt"
else
    fileName="$dirName/$customName.txt"
fi

You could compress that all into one line, but that sacrifices clarity immensely.

Is there any better way of writing an inline if with variable assignment in shell?

Community
  • 1
  • 1
IQAndreas
  • 8,060
  • 8
  • 39
  • 74
  • William Purcell's answer is less direct than mine, but if the assumption that `$useDefault` controls whether to use the default name or not, it might be a cleaner solution. – Keith Thompson Jan 01 '13 at 00:58
  • I've updated my answer to quote everything properly. – Keith Thompson Jan 01 '13 at 20:43
  • ```fileName="$dirName/$([ $useDefault ] && echo "$defaultName" || echo "$customName").txt"``` I think this is as close to ```?:``` as possible. – Christoph Apr 28 '21 at 21:31

2 Answers2

19

Just write:

fileName=${customName:-$defaultName}.txt

It's not quite the same as what you have, since it does not check useDefault. Instead, it just checks if customName is set. Instead of setting useDefault when you want to use the default, you simply unset customName.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Could you provide more information on this `:-` operator? (or at least some name for it that I can search Google with) – IQAndreas Jan 01 '13 at 02:50
  • 1
    Just search for `:-` in the bash man page. Any `sh` documentation will describe this under headings like `parameter expansion`. – William Pursell Jan 01 '13 at 03:44
  • 4
    For `bash`, see [parameter expansion](http://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion); for POSIX shell, see [parameter expansion](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02). – Jonathan Leffler Jan 01 '13 at 05:52
  • great introduction and then building up to it: http://wiki.bash-hackers.org/syntax/pe#use_an_alternate_value – Frank N Feb 25 '17 at 11:30
  • I like this one, it's like the // operator ("Undefined-or") in Perl which I always use for assigning default values. – Christoph Apr 28 '21 at 20:39
12

There is no ?: conditional operator in the shell, but you could make the code a little less redundant like this:

if [ $useDefault ]; then
    tmpname="$defaultName"
else
    tmpname="$customName"
fi
fileName="$dirName/$tmpname.txt"

Or you could write your own shell function that acts like the ?: operator:

cond() {
    if [ "$1" ] ; then
        echo "$2"
    else
        echo "$3"
    fi
}

fileName="$dirname/$(cond "$useDefault" "$defaultName" "$customName").txt"

though that's probably overkill (and it evaluates all three arguments).

Thanks to Gordon Davisson for pointing out in comments that quotes nest within $(...).

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • I really like the `cond` function, which is the reason I accepted the answer, though the first solution does save repetitious code as well. – IQAndreas Jan 01 '13 at 02:49
  • You should leave the `$(cond ... )` inside the double-quotes (i.e. `fileName="$dirname/$(cond "$useDefault" "$defaultName" "$customName").txt"`) -- that'll prevent some almost-certainly-unwanted extra parsing on the string cond returns. – Gordon Davisson Jan 01 '13 at 04:15
  • @GordonDavisson: I thought about that, but it leaves the variable references `$useDefault` et al outside the quotes. I'm not sure there's a good solution. – Keith Thompson Jan 01 '13 at 10:17
  • 1
    @KeithThompson: That's not a problem; quotes nest with `$()`, so `$useDefault` will be treated as double-quoted either way. – Gordon Davisson Jan 01 '13 at 19:20