3

I would like to combine default assignment, as seen here, with conversion to lowercase, as seen here.

This is what I'm working with:

bash-3.2$ export MY_ENV_VAR=FaLsE
bash-3.2$ : "${MY_ENV_VAR:=false}"
bash-3.2$ echo $MY_ENV_VAR
FaLsE

I would like to set the value of MY_ENV_VAR to lowercase in a single statement since I have 20+ lines of code grabbing values of environment variables and I'd rather not add 20+ additional lines to do the conversion by itself.

I've tried a few things, like:

bash-3.2$ : "${MY_ENV_VAR:=false,,}"
bash-3.2$ echo $MY_ENV_VAR
FaLsE

That method seems like it would work if I had Bash 4 but I'm on 3.2.

I've also tried:

bash-3.2$ myval=$(: "${MY_ENV_VAR:=false}" | tr '[:upper:]' '[:lower:]')
bash-3.2$ echo $myval

bash-3.2$

And:

bash-3.2$ myval=$(: echo "${MY_ENV_VAR:=false}" | tr '[:upper:]' '[:lower:]')
bash-3.2$ echo $myval

bash-3.2$

Which I didn't expect to work but I don't understand the default assignment enough to know how that would be used to feed the conversion to lowercase. I find certain features of Bash difficult to understand.

harperville
  • 6,921
  • 8
  • 28
  • 36
  • As simple as that with Bash: `export MY_ENV_VAR=FaLsE; MY_ENV_VAR=${MY_ENV_VAR,,}; MY_ENV_VAR=${MY_ENV_VAR:=false}` – Léa Gris Jun 29 '22 at 14:56
  • Universal Bash function to export lowercased value or default. Arg1 is variable name to export, Arg2 is default value. `exportLowerDefault() { v=${!1};v=${v,,};v=${v:=$2};export "$1=$v";}` – Léa Gris Jun 29 '22 at 15:28

4 Answers4

3

Since you are using Bash, use built-in case modification:

#!/bin/bash

export MY_ENV_VAR=
for MY_ENV_VAR in FaLsE '' tRuE
do
  # Expands to lower-case
  MY_ENV_VAR=${MY_ENV_VAR,,}

  # Assigns default value
  MY_EN_VAR=${MY_ENV_VAR:=false}

  # Prints it to see
  printf 'MY_ENV_VAR=%s\n' "$MY_ENV_VAR"
done

Actual output is as expected:

MY_ENV_VAR=false
MY_ENV_VAR=false
MY_ENV_VAR=true

Now, rather than repeating this 20+ times for every variable, then make it into a function:

exportLowerDefault() {
  local -- v=${!1}
  v=${v,,}
  v=${v:=$2}
  export "$1"="$v"
}

for MY_ENV_VAR in FaLsE '' tRuE
do
  exportLowerDefault MY_ENV_VAR false

  # Prints it to see
  printf 'MY_ENV_VAR=%s\n' "$MY_ENV_VAR"
done
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
2

Unfortunately, you cannot use nested substitution in bash (and most other shells).

However, in your specific case you can use tools such a tr to handle the lowercase conversion, and use variable substitution to handle the default value.

For instance :

MY_ENV_VAR=$(tr [:upper:] [:lower:] <<< ${MY_ENV_VAR:=false})

Another (uglier) solution would be to use a subshell :

MY_ENV_VAR=$(TMP=${MY_ENV_VAR,,}; echo "${TMP:=false}")
Aserre
  • 4,916
  • 5
  • 33
  • 56
  • This does not gain anything against sequential substitutions for lower-casing and assigning a default value. Spawning the sub-shell and pipeline may cost even more in the end, compared to sequential expansions. – Léa Gris Jun 29 '22 at 15:09
  • @LéaGris quotting from the original question : `I would like to set the value of MY_ENV_VAR to lowercase in a single statement since I have 20+ lines of code grabbing values of environment variables`. For environment variables, the performance cost should be negligible compared to sequencial substitution – Aserre Jun 29 '22 at 15:12
1

A function is an entity for encompassing a sequence of repeated tasks.

set_default_value_and_conver_to_lowercase() {
   declare -n _var=$1
   : "${_var:-$2}"
   _var=${_var,,}
}

set_default_value_and_conver_to_lowercase MY_ENV_VAR false

For that old bash3, you could use eval instead of namereference, hopefully with some error checking:

set_default_value_and_conver_to_lowercase() {
   local _var
   if ! <<<"$1" grep -qx '[A-Z_]*'; then exit 1; fi
   eval "_var=\${$1}"
   : "${_var:-$2}"
   _var=${_var,,}
   printf -v "$1" "%s" "$_var"
}

set_default_value_and_conver_to_lowercase MY_ENV_VAR false
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • +1 This answers the next question that came up while doing this and while I'd like to accept it as the answer, @Aserre's answer above is the most direct answer to this question. – harperville Jun 29 '22 at 15:33
0

This seems to work for me -

MY_ENV_VAR=$(tr [:upper:] [:lower:] <<< $MY_ENV_VAR)
echo $MY_ENV_VAR
# false
Mortz
  • 4,654
  • 1
  • 19
  • 35