0

How can I make this into a loop? I have trouble with looping through variables.

WSTATUS="exited" //example output from command
VSTATUS="running"
NSTATUS="running"
JSTATUS="running"


if [[ $WSTATUS == run* ]]; then
    WSTATUS=${GREEN}$WSTATUS
else
    WSTATUS=${RED}$WSTATUS
fi


if [[ $VSTATUS == run* ]]; then
    VSTATUS=${GREEN}$VSTATUS
else
    VSTATUS=${RED}$VSTATUS
fi


if [[ $NSTATUS == run* ]]; then
    NSTATUS=${GREEN}$NSTATUS
else
    NSTATUS=${RED}$NSTATUS
fi


if [[ $JSTATUS == run* ]]; then
    JSTATUS=${GREEN}$JSTATUS
else
    JSTATUS=${RED}$JSTATUS
fi

I have tried this:

...varibles

array=( $WSTATUS $VSTATUS $NSTATUS $JSTATUS )

for value in "${array[@]}"
do
    if [[ $value == run* ]]; then
        WSTATUS=${GREEN}$value
    else
        WSTATUS=${RED}$value
    fi
done

How can i iterate through bash variables, not their content? changing this wstatus into value does not work --> WSTATUS=${GREEN}$value

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
tama3ti
  • 5
  • 3
  • This is easier if they share a common _prefix_ instead of a common suffix; there are several "loop through variables starting with these letters" options available. – Charles Duffy Sep 24 '22 at 21:36
  • BTW, all-caps names are used for variables meaningful to POSIX-defined tools; you should use lowercase names for your own variables to avoid changing the behavior of OS-provided tools by mistake. See relevant specification @ https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html – Charles Duffy Sep 24 '22 at 21:37
  • In addition to the linked duplicates, see [BashFAQ #6](https://mywiki.wooledge.org/BashFAQ/006): *How can I use variable variables (indirect variables, pointers, references) or associative arrays?* – Charles Duffy Sep 24 '22 at 21:40

3 Answers3

1

Not a loop, but a function already helps a lot:

colorme() {
  if [[ "$1" == run* ]]; then
    printf '%s' "${GREEN}$1"
  else
    printf '%s' "${RED}$1"
  fi
}

WSTATUS=$(colorme "$WSTATUS")
VSTATUS=$(colorme "$VSTATUS")
NSTATUS=$(colorme "$NSTATUS")
JSTATUS=$(colorme "$JSTATUS")
knittl
  • 246,190
  • 53
  • 318
  • 364
1

You can use nameref (declare -n var in following script)

#!/usr/bin/env bash

GREEN=GREEN
RED=RED

WSTATUS="exited"
VSTATUS="running"
NSTATUS="running"
JSTATUS="running"

array=( WSTATUS VSTATUS NSTATUS JSTATUS )
declare -n var

for var in "${array[@]}"
do
    [[ $var == run* ]] && prefix="${GREEN}" || prefix="${RED}"
    var="$prefix$var"
done

declare -p WSTATUS VSTATUS NSTATUS JSTATUS
Philippe
  • 20,025
  • 2
  • 23
  • 32
  • Nice. I'm not used to this one. And the fact that as control variable of the for loop, it is var (the reference) that iterates, not whatever variable it references. – chrslg Sep 24 '22 at 21:52
0

What you are looking for is declare and ! expansion

a=b
declare $b=12
echo $b

=> 12

That is for setting a variable whose name is computed (here from another variable)

echo ${!a}

=> 12 That is for accessing the content of a variable whose name is stored in another variable

So in your case, it may look like

WSTATUS="exited" //example output from command
VSTATUS="running"
NSTATUS="running"
JSTATUS="running"

totest=( WSTATUS VSTATUS NSTATUS JSTATUS )

for name in ${array[@]}
do
    if [[ ${!name} == run* ]]; then
       declare $name=${GREEN}${!name}
    else
       declare $name=${RED}${!name}
    fi
done

Copying without any other modification your script. I have some reservation about the idea to add those, apparently green and red escape code to the variable content, rather than taking this decision at print time. I didn't really try do understand nor the test neither the action your script is taking. Even, (XY problem parenthesis) the fact that what you need is to loop through variable is questionable. knittl solution, tho it does not answer to your question, is probably a better solution to your real problem.

But well, your question was how to loop through variable. This is a way to do it.

chrslg
  • 9,023
  • 5
  • 17
  • 31
  • 1
    `declare` is _a_ way to do indirect assignment, but it's nothing like _the only_ way. namerefs are arguably superior if there's no need for compatibility with old bash releases; or `printf -v` if there is. – Charles Duffy Sep 24 '22 at 21:38
  • @CharlesDuffy I never told, or even thought it was the only way. Even before I heard about nameref (and that was 15 minutes ago, when I read Philippe's answer). As for nameref, I agree, it is (from what I can tell after 15 minutes of knowing about it) a better solution. Alas, I didn't know about them when I wrote my answer. – chrslg Sep 24 '22 at 21:56