Question: I would like to write a loop in bash which executes until a certain command stops failing (returning non-zero exit code), like so:

```
while ! my_command; do
    # do something
done

```

But inside this loop I need to check which exit code `my_command` returned, so I tried this:

```
while ! my_command; do
    if [ $? -eq 5 ]; then
        echo "Error was 5"
    else
        echo "Error was not 5"
    fi
    # potentially, other code follows...
done

```

But then the special variable `?` becomes `0` inside the loop body.
The obvious solution is:

```
while true; do
    my_command
    EC=$?
    if [ $EC -eq 0 ]; then
        break
    fi
    some_code_dependent_on_exit_code $EC
done

```

How can I check the exit code of `my_command` (called in loop header) inside loop body without rewriting this example using a `while true` loop with a break condition as shown above?

Answer: 
In addition to the well-known `while` loop, POSIX provides an `until` loop that eliminates the need to negate the exit status of `my_command`.

```
# To demonstrate
my_command () { read number; return $number; }

until my_command; do
    if [ $? -eq 5 ]; then
        echo "Error was 5"
    else
        echo "Error was not 5"
    fi
    # potentially, other code follows...
done

```
So in my case I also need to ignore some exit codes and want to provide some useful output to the user so I wrote this up:

```
retrycmd(){
  MSG=$1
  IGNORE=$2
  shift 2
  local SLEEP_T=5
  local L_CNT=5
  local C_CNT=0
  while ((C_CNT++ < ${L_CNT})) && ! $@;do
    RET=${PIPESTATUS[0]}
    #echo "RET: ${RET}"
    for I in ${IGNORE//,/ };do # bashism: replace(/) all(/) match(,) with(/) value(<space>)
      if ((${RET} == ${I}));then
        #echo "${RET} = ${I}"
        break 2
      fi
    done
    echo "${MSG} failure ${C_CNT}"
    sleep ${SLEEP_T}
  done
  if ((${C_CNT} > ${L_CNT}));then
    echo "${MSG} failed"
    poweroff
  fi
}

#retrycmd "Doing task" "IGNORE,CSV" <CMD>
retrycmd "Ping google" "0" ping www.google.com

```