Using arrays in bash using strings to bash built-in true

I have the following code and for some reason when I call the program using

/home/tcdata/tatsh/trunk/hstmy/bin/bash/raytrac.bash --cmod=jcdint.cmod

I get

hasArgument[usage] = 
hasArgument[usage] = true

Somehow the array element

is returning

even though I have not chosen the

option.

#!/bin/bash

#--Initialization----------------------------------------------------------------------------------

# Recognize both the -n flag and backslashed escape sequences.
echo_style="both"

ierr=0
Dflt_rytrVblv="medium"
Dflt_vblevel=1
Dflt_shiftLen=3
Dflt_bdVblevel=1

vb_usrInputFlag=0

# --Read Command Line Arguments---------------------------------------------------------------------

# IFS is a special variable that controls splitting. We split on "|" and "=", not whitespace.
# "$*" will now become a string like a|b|c

# Split on | and =.  $* will insert the | itself when IFS="|", so we
# get back what we put in, except everything's now split on = too, i.e.
# "a b" "c" --option=file
# becomes
# "a b" "c" --option file


# Return IFS to its normal whitespace.

# Loop until all arguments are used up.
# Shift tosses the value of $1 and sets $1=$2, $2=$3, ...
# so doing this repeatedly will decrease the value of $# until
# we run out of arguments.

OLDIFS="$IFS"
IFS="|="                # IFS controls splitting. Split on "|" and "=", not whitespace.
set -- $*               # Set the positional parameters to the command line arguments.
IFS="$OLDIFS"

narg="$#"
opt_browseDir_flag=`echo "$*" | tr '' '' | awk '/BRWS/ {print 1}; ! /BRWS/ {print 0}'`
echo "\$* = $*"

echo "hasArgument[usage] = ${hasArgument[usage]}"

while [ "$#" -gt 0 ]
do

  case "$1" in

  "--"[rR][yY][tT][rR][pP][tT][hH]|\
  "--"[rR][yY][tT][rR]"-"[pP][[aA][tT][hH])
    shift               # Skip ahead one to the next argument.
    value[rytrPath]="${1}"
    hasArgument[rytrPath]=true
  ;;

  "--"[cC][mM][oO][dD]|\
  "--"[cC][mM][oO][dD]"-"[iI][fF][lL])
    shift
    value[cmodInfl]="${1}"
    hasArgument[cmodIfl]=true
  ;;

  "--"[sS][rR][cC][sS]|\
  "--"[sS][rR][cC][sS]"-"[iI][fF][lL])
    shift
    value[srcsInfl]="${1}"
    hasArgument[srcsIfl]=true
  ;;

  "--"[rR][cC][vV][sS]|\
  "--"[rR][cC][vV][sS]"-"[iI][fF][lL])
    shift
    value[rcvsInfl]="${1}"
    hasArgument[rcvsIfl]=true
  ;;

  "--"[pP][hH][sS][sS]|\
  "--"[pP][hH][aA][sS][eE][sS])
    shift
    value[phases]="${1}"
    hasArgument[phases]=true
  ;;

  "--"[vV][bB][lL][vV]|\
  "--"[vV][bB]"-"[lL][eE][vV][eE][lL])
    shift
    value[vblv]="${1}"
    hasArgument[vblv]=true
  ;;

  "--"[fF][mM][tT]|\
  "--"[fF][oO][rR][mM][aA][tT])
    shift
    value[fmt]="${1}"
    hasArgument[fmt]=true
  ;;

  "--"[dD][tT][aA][uU])
    shift
    value[dtau]="${1}"
    hasArgument[dtau]=true
  ;;

  "--"[bB][rR][aA][cC][dD]|\
  "--"[bB][rR][aA][cC]"-"[dD][iI][sS][tT])
    shift
    value[bracD]="${1}"
    hasArgument[bracD]=true
  ;;

  "--"[tT][wW][pP][tT][dD]|\
  "--"[tT][wW][pP][tT]"-"[dD][iI][sS][tT])
    shift
    value[twptD]="${1}"
    hasArgument[twptD]=true
  ;;

  "--"[tT][wW][pP][tT][iI][tT][mM][xX]|\
  "--"[tT][wW][pP][tT]"-"[iI][tT][mM][aA][xX])
    shift
    value[twptItmax]="${1}"
    hasArgument[twptItmx]=1
  ;;

  "--"[rR][aA][yY][sS]|\
  "--"[rR][aA][yY][sS]"-"[oO][fF][lL])
    shift
    value[raysOutfl]="${1}"
    hasArgument[raysOfl]=1
  ;;

  "--"[tT][rR][vV][tT]|\
  "--"[tT][rR][vV][tT]"-"[oO][fF][lL])
    shift
    value[trvtOutfl]="${1}"
    hasArgument[trvtOfl]=true
  ;;

  "--"[rR][yY][tT][rR]"-"[vV][bB]|\
  "--"[rR][yY][tT][rR]"-"[vV][bB][lL][vV])
    shift
    value[rytrVblv]="${1}"
    hasArgument[rytrVb]=true
  ;;

  "--"[pP][mM][fF][lL])
    shift
    value[pmfl]="${1}"
    hasArgument[pmfl]=true
  ;;

  "--"[rR][yY][tT][rR][cC][bB][gG]|\
  "--"[rR][yY][tT][rR][cC]"-"[bB][gG])
    hasArgument[rytrBg]=true
  ;;

  "--"[bB][dD][pP][tT][hH]|\
  "--"[bB][dD][iI][rR]"-"[pP][aA][tT][hH])
    value[bdPath]="${1}"
    hasArgument[bdPath]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD]"-"[cC][oO][lL][pP]|\
  "--"[bB][dD][iI][rR]"-"[cC][oO][lL][pP][oO][sS])
    hasArgument[bdColp]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][sS][rR][tT]|\
  "--"[bB][dD][iI][rR]"-"[sS][oO][rR][tT])
    shift
    value[bdsrt]="${1}"
    hasArgument[bdSrt]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][gG][rR][pP]|\
  "--"[bB][dD][iI][rR]"-"[gG][rR][oO][uU][pP])
    shift
    value[bdGrp]="${1}"
    hasArgument[bdGrp]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][A][L][L]|\
  "--"[bB][dD][iI][rR]"-"[A][L][L])
    hasArgument[bdAll]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][rR][yY][tT][rR]|\
  "--"[bB][dD][iI][rR]"-"[rR][yY][tT][rR])
    hasArgument[bdRytr]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][dD][rR][wW]|\
  "--"[bB][dD][iI][rR]"-"[dD][rR][wW])
    hasArgument[bdDrw]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][sS][mM][pP]|\
  "--"[bB][dD][iI][rR]"-"[sS][mM][pP])
    hasArgument[bdSmp]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][lL][oO][gG]|\
  "--"[bB][dD][iI][rR]"-"[lL][oO][gG])
    hasArgument[bdLog]=true
    hasArgument[bd]=true
  ;;

  "--"[bB][dD][mM][sS][fF]|\
  "--"[bB][dD][iI][rR]"-"[mM][sS][fF])
    hasArgument[bdMsf]=true
    hasArgument[bd]=true
  ;;

  "-"[vV][bB][lL][vV]|\
  "--"[vV][bB]"-"[lL][eE][vV][eE][lL])
    shift
    value[vbLv]="${1}"
    hasArgument[vblv]=true
  ;;

  "-q"|"--quiet")
    hasArgument[quiet]=true
    hasArgument[vb]=false
  ;;

  "-u"|"--usage")
    hasArgument[usage]=true
  ;;

  "-e"|"--examples")
    hasArgument[examples]=true
  ;;

  "-h"|"--help")
    hasArgument[help]=true
  ;;

  *)
    value[bdFileLst]="${value[bdFileLst]} ${1}"
    hasArgument[bdFileLst]=true
    hasArgument[bd]=true
  ;;

  esac

  shift                 # Skip ahead to the next argument

done

# --Print Header------------------------------------------------------------------------------------

allArgs="$*"

raytracProg="./raytrac.tcsh"
eg1="$raytracProg --cmodif"
eg2="$raytracProg --cmodif"
eg3="$raytracProg --cmodif"

echo "hasArgument[usage] = ${hasArgument[usage]}"

BASH doesn't have boolean types. The existence of a program named 'true' doesn't change this.

BASH doesn't have associative arrays, either. You can't use words as array indexes.

That's a bit of a problem. Doing

in section arrays, says that Bash provides one-dimensional indexed and associative array variables. Should work from bash 4.0 onward.

ksh should have associative arrays and can use the same logic. What would be the alternative to the true/false scheme I used. For single variables, the true/false should work. Or am I wrong in the conclusion. I tried it and did not encounter a problem.

---------- Post updated at 11:18 AM ---------- Previous update was at 10:37 AM ----------

This is funny

echo "HELLO"
hasArgument[mytest0]=0
hasArgument[mytest1]=1
hasArgument[mytest2]=2
echo "${hasArgument[mytest0]} ${hasArgument[mytest1]} ${hasArgument[mytest2]}"

This returns

HELLO
2 2 2

If you only need your script to run in the 1% of the world that has a new enough version of bash, yes...

Try quoting your strings.

VAR['asdf']=1
echo "${VAR['asdf']}"

What's the string quoting about?

It works either way for me, but I doubt we have identical bash versions, try it, see if it works.

How about ksh? Can I use associative arrays without worry about using them?

Can one do the following in bash?

false=0
true=1

It works but one has to define the array as associative using:

declare -A VAR

How about trying what I suggested? Did it work, or did it not?

BASH is not C. I don't see any point in doing this. It's not going to make your code simpler. All you're going to do is make your code more and more complicated and strange.

Learn a tiny bit more about shell programming instead. Use variables as they're intended to be used. It looks unfamiliar to you because it's not familiar. Once you recognize it, it won't be.

What I would do is use bash's -z flag to tell if variables are empty. That way, you don't have to set a thousand different empty variables to zero -- just leave them blank. If they're still blank after processing options, then nobody set them.

case "$1" in
--something)
        SOMETHING=1
        ;;
esac

if [ ! -z "$SOMETHING" ]
then
        echo "Someone passed the --something option"
fi
1 Like

You could also try Perl, which has associative arrays too, but I think that's just going to make it even more complicated.

I fully agree with you. I had ended up in the situation you describe, with the code getting too complicated. I was looking at removing the setting of lots of variables to zero.

Getting my code on this forum was a way to get input on the way forward. So thanks a lot for your contribution.

---------- Post updated at 12:38 PM ---------- Previous update was at 12:35 PM ----------

Yes, I tried perl and got things more complicated. So abandoned the perl strategy.

I think functions may be helpful to you in simplifying your code, and making it look better to you. In BASH and some KSH you can do this:

function isset # varname
{
        [ -z "${!1}" ]
}

function notset # varname
{
        [ ! -z "${!1}" ]
}

if isset VARIABLE # Note the lack of $
then
        echo "VARIABLE is set, its value is $VARIABLE"
fi

if notset VARIABLE
then
        echo "VARIABLE is not set"
fi
1 Like

Here is an illustration. Unsure if I need to have

anymore.

OLDIFS="$IFS"
IFS="|="                # IFS controls splitting. Split on "|" and "=", not whitespace.
set -- $*               # Set the positional parameters to the command line arguments.
IFS="$OLDIFS"

declare -A hasArgument

while [ "$#" -gt 0 ]
do

  case "$1" in

  "--"[cC][mM][oO][dD]|\
  "--"[cC][mM][oO][dD]"-"[iI][fF][lL])
    shift
    value_cmodIfl="$1"
    hasArgument_cmodIfl=1
  ;;

  "--"[sS][rR][cC][sS]|\
  "--"[sS][rR][cC][sS]"-"[iI][fF][lL])
    shift
    value_srcsIfl="$1"
    hasArgument_srcsIfl=1
  ;;

  "--"[rR][cC][vV][sS]|\
  "--"[rR][cC][vV][sS]"-"[iI][fF][lL])
    shift
    value_rcvsIfl="$1"
    hasArgument_rcvsIfl=1
  ;;

  *)
    value_bdFileLst="$value_bdFileLst $1"
    hasArgument_bdFileLst=1
    hasArgument_bd=1
  ;;

  esac

  shift                 # Skip ahead to the next argument

done

if [ ! -z "$value_cmodIfl" ]
then
   cmodIfl="$value_cmodIfl"
else
   cmodIfl="$dflt_cmodIfl"
fi

I don't think you need any of them at all. You can tell if the variables are blank, why waste more variables storing things you can tell without them?

Also -- just set your defaults in the first place, and let the script change them later if they're given.

OLDIFS="$IFS"
IFS="|="                # IFS controls splitting. Split on "|" and "=", not whitespace.
set -- $*               # Set the positional parameters to the command line arguments.
IFS="$OLDIFS"

# Just set the default in the first place.
value_cmodIfl="$dflt_cmodIfl"

while [ "$#" -gt 0 ]
do
  case "$1" in

  "--"[cC][mM][oO][dD]|\
  "--"[cC][mM][oO][dD]"-"[iI][fF][lL])
    shift
    value_cmodIfl="$1"
  ;;

  "--"[sS][rR][cC][sS]|\
  "--"[sS][rR][cC][sS]"-"[iI][fF][lL])
    shift
    value_srcsIfl="$1"
  ;;

  "--"[rR][cC][vV][sS]|\
  "--"[rR][cC][vV][sS]"-"[iI][fF][lL])
    shift
    value_rcvsIfl="$1"
  ;;

  *)
    value_bdFileLst="$value_bdFileLst $1"
  ;;

  esac

  shift                 # Skip ahead to the next argument

done

if [ ! -z "$value_rcvsIfl" ]
then
        echo "rcvsIfl given"
fi

I am getting a bit of problems with the following.

Output shows

agr1 set to 
agr2 set to file.cmod
#!/bin/bash

function isSet
{
    [ ! -z "$1" ]
}

function notSet
{
    [ -z "$1" ]
}

agr2="file.cmod"

if isSet agr1; then
  echo "agr1 set to $agr1"
fi

if notSet agr1; then
  echo "agr1 not set"
fi

if isSet agr2; then
  echo "agr2 set to $agr2"
fi

if notSet agr2; then
  echo "agr2 not set"
fi

You're always so fast, and I have a habit of editing in minor fixes later. Check my post again.

[ ! -z "$1" ]

vs

[ ! -z "${!1}" ]

I agree with you. One problem is that some defaults require the use of mandatory values defined by the user, so I cannot put them all at the beginning. The result was that some defaults occurred in the beginning and some after the while loop. This used to be ok, but when amount of options got larger, it seems a good idea to group them all after the while loop.

---------- Post updated at 01:16 PM ---------- Previous update was at 01:08 PM ----------

Seems to work now with the following modifications

function isSet
{
    [ ! -z "${!1}" ]
}

function notSet
{
    [ -z "${!1}" ]
}

If you have lots and lots of optional, default, and mandatory values, you can do something like this:

# File listing variables and default values
# Mandatory value causes error if not set, printing errormessage from file
var1 mandatory errormessage
# Optional variable gets set to defaultvalue when absent
var2 optional defaultvalue
var3 optional defaultvalue
var4 optional defaultvalue
while read VAR TYPE STR
do
        [ -z "$VAR" ] && continue # Skip blank lines
        [ "${VAR:0:1}" = "#" ] && continue # Skip comments

        case "$TYPE" in
        mandatory)
                if [ -z "${!VAR}" ] # Blank variable is an error
                then
                        echo "$VAR not set:  $STR"
                        exit
                fi
                ;;

        *)        # If blank, set default
                   # <<< is a BASH-only syntax.
                   [ -z "${!VAR}" ] && read VAR <<<"$STR"
                ;;
        esac
done < variablefile

Having a bit of difficulty seeing where this fits in.

I use the script in the following way:

cd testPath
/thePath/script.bash/raytrac.bash --cmod=file.cmod

In this case the program will search in directory testPath for files

.srcs and .rcvs 

Other options, for example:

This is either set by the user using --nameOfl=name or take the name of the cmod file (call it cmodName) to create the

raysOfl="cmodName.ry" and trvtOfl="cmodName.xt" 

That won't do what you want then, no.

I do not want the user to input the options interactively. The idea is that the user sets up a script with the sequence of operations he wants (run scripts and C++ programs), run the script, and no user requests are ever done. He then waits for the script to finish. In the meantime, he can check and do some analysis of the results as the sequence progresses.