1
TOKEN=$(if [[ $TOKEN ]] then echo $TOKEN else cat ./cloud/token fi)

So I'm trying to set the variable TOKEN. This might of been set previously in which case I'd like for that value to be used and if not I'd like for it to be assigned by catting a file.

The above doesn't work as my skills in bash are lacking!

basickarl
  • 37,187
  • 64
  • 214
  • 335
  • Your code is correct, you just failed to add `;`. This should work `TOKEN=$(if [[ $TOKEN ]]; then echo $TOKEN; else cat ./cloud/token; fi)` – HatLess Nov 17 '21 at 16:11

6 Answers6

6

You can simplify this by using bash's support for default parameter values. From the 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.

For your example, you can do this:

TOKEN=${TOKEN:-$(cat ./cloud/token)}
jordanm
  • 33,009
  • 7
  • 61
  • 76
3

In this particular case, I would use parameter substitution and specify a default value which is used when the variable is not defined:

TOKEN=${TOKEN-$(< ./cloud/token)}
marbu
  • 1,939
  • 2
  • 16
  • 30
  • The problem with this is that you are running `cat` every time, regardless of if `TOKEN` is empty or not. It's good if the default is a literal string, but not for a command sub, generally speaking. – dan Nov 17 '21 at 16:46
  • Hmm, I just tried that and I see that it doesn't access the token file if `TOKEN` variable is not defined. Tested with bash 5.1.0. – marbu Nov 17 '21 at 16:56
  • 1
    I think you mean _is_ defined, but sorry I was wrong. I always thought command subs were expanded by the shell first, but they are handled differently here. I found clear documentation in [POSIX 2018](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html): `In this example, ls is executed only if x is null or unset ${x:-$(ls)}`. I verified with colon and without, using `${foo-$(sleep 1)}`. – dan Nov 17 '21 at 17:46
  • This is a UUOC case, because Bash can always read files without `cat`: `TOKEN=${TOKEN-$(< ./cloud/token)}` – Andrej Podzimek Nov 17 '21 at 20:36
  • Another side note: The `:-` version may be more appropriate in some situations. `TOKEN=${TOKEN:-$(< ./cloud/token)}` The `man` page contains all the details. – Andrej Podzimek Nov 17 '21 at 20:39
  • Good point about cat usage, I updated the answer. – marbu Nov 18 '21 at 10:08
1

You can use :

: ${TOKEN:=$(cat ./cloud/token)}
Philippe
  • 20,025
  • 2
  • 23
  • 32
0
TOKEN=$([ -n "$TOKEN" ] && echo "$TOKEN" || cat ./cloud/token)
Cyrille Pontvieux
  • 2,356
  • 1
  • 21
  • 29
  • 1
    This works here, but the pattern can be a bit weird because there are cases where `bash` will execute both (eg if instead of `echo` it was something that can fail) – jordanm Nov 17 '21 at 16:06
  • you can use `&& (something-that-fails-but-output-something; true)` – Cyrille Pontvieux Nov 17 '21 at 16:21
0

I think that semicolons are necessary.

TOKEN=$(if [[ $TOKEN ]]; then echo $TOKEN; else cat ./cloud/token; fi)
kei-g
  • 88
  • 3
0
TOKEN=$(if [ -z "${TOKEN}" ]; then cat ./cloud/token; else echo "${TOKEN}"; fi)

The -z condition checks whether the variable is empty or whether any value is assigned. If the condition is met (i.e., the variable is empty) that means it has to look for value from the ./cloud/token file. If the condition fails, that means the value is already assigned, so it then echoes the variable.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
SuS
  • 61
  • 1
  • 10