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?

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)

  • 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. – 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