0

I am new in shell scripting. I have written a simple script to assign variable conditionally:

#!/bin/sh

my_env=$1

if (my_env=="dev"); then
  MY_TYPE="dev type"
elif (my_env=="stg"); then
  MY_TYPE="stg type"
elif (my_env=="prod"); then
  MY_TYPE="prod type"
fi
echo $MY_TYPE

When I run it:

$shell ./my_script.sh dev

It prints out: dev type, which is correct.

after that, I run again with :

$shell ./my_script.sh stg

It also print out dev type. Why it doesn't print out stg type?? Where is wrong in my conditional logic?

user842225
  • 231
  • 1
  • 2
  • 6

1 Answers1

3

The sh language is not the C language, you can't just expect one thing that works in one language will work in another language.

sh is before all a command line interpreter. Most things are done by commands which the shell is there to invoke.

For instance, to evaluate conditional tests, there's a dedicated command for that: [ aka test. The if/then/fi is a syntax structure of sh, but its action is based on the success or failure of the command list that is in-between if and then.

For the contents of a variable to be passed to a command, you need the $var syntax. echo foo passes foo to the echo command, echo "$foo" passes the contents of the $foo variable to echo (note the quotes which are important (even critical in the case of the [ command) in sh to work around an unfortunate misfeature).

In sh, (...) is to run a subshell, for the code within to be interpreted in a separate environment (in most sh implementations, in a child process), and my_env=="dev" is just the same as my_env="=dev"¹ which assigns =dev to the $my_env variable, which it will succeed to do, so the subshell will also be successful, so the then part will be run.

The correct syntax would be:

#!/bin/sh -

my_env="$1"

if [ "$my_env" = dev ]; then
  MY_TYPE="dev type"
elif [ "$my_env" = stg ]; then
  MY_TYPE="stg type"
elif [ "$my_env" = prod ]; then
  MY_TYPE="prod type"
fi
printf '%s\n' "$MY_TYPE"

Though here, you'd rather use a case construct (similar to C's switch):

#! /bin/sh -
my_env=${1?Missing type argument}

case $my_env in
  (dev | stg | prod)
    MY_TYPE="$my_env type"
    ;;
  (*)
    printf >&2 '%s\n' "Unsupported type: $my_env"
    exit 1
esac

printf 'MY_TYPE = %s\n' "$MY_TYPE"

See also the catch-all that exits with a failure exit status if $my_env is not among an allowed set to avoid $MY_TYPE be used uninitialised below, and the ${1?error} as a quick way to ensure the script is passed at least one argument and report an error to the user if not.


¹ or my_env='=dev' or my_env==dev or my_env='='"d"e\v, but not my_env'==dev' nor $my_dev==dev, the important part being that the first = be literal and unquoted and what's left of it be literal, unquoted and a valid variable name for it to be taken as a variable assignment command. my_env'==dev' would try and run a command called my_env==dev (and likely fail to find it)

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • Thanks for the answer, since I am new in shell, just out of my curiosity, is bash script more favoured/recommended than shell ? I am now converting my script to bash, so, could you please help providing a counter-part bash script since my script is very simple. Thanks in advance. – user842225 Mar 07 '22 at 08:56
  • @user842225, `bash` supports the `sh` language syntax, even more closely when it's itself invoked as `sh` so this code will work in `bash` as well. I'm not a big fan of `bash` myself, as it has copied most of the misfeature of `ksh`. For shells with some *improvements* over the POSIX `sh` syntax, you can have a look at shells like `rc`, `zsh` or `fish` (among which `zsh` is the most `sh`-like). – Stéphane Chazelas Mar 07 '22 at 09:29
  • Thanks. I try to capitalize all letters from input, I tried `my_env=${1^^?Missing type argument}`. but end up with error `line 2: ${1^^?Missing type argument}: bad substitution`, could you please help on this? I see people using `^^` to capitalize all letters, why not working with my syntax? – user842225 Mar 07 '22 at 09:33
  • `${var^^}` is bash syntax, not sh syntax. See also `$var:u` or `${(U)var}` in zsh. But bash (contrary to zsh) has very limited support for combining parameter expansion operators, so you'd need to do it in two steps there. The specification of the `sh` language can be found [there](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18). – Stéphane Chazelas Mar 07 '22 at 09:42
  • How can I wrap it in a function and call the function in the same shell script file? – user842225 Mar 07 '22 at 09:49