How to Get the Exit Status a Loop in Bash

How to get the exit status a loop in bash

The status of the loop is the status of the last command that executes. You can use break to break out of the loop, but if the break is successful, then the status of the loop will be 0. However, you can use a subshell and exit instead of breaking. In other words:

for i in foo bar; do echo $i; false; break; done; echo $?  # The loop succeeds
( for i in foo bar; do echo $i; false; exit; done ); echo $? # The loop fails

You could also put the loop in a function and return a value from it. eg:

in() { local c="$1"; shift; for i; do test "$i" = "$c" && return 0; done; return 1; }

Bash exit status when using while loop

Your first problem is that by doing cat file | while read you've spawned the while in its own subshell. Any variables it sets will only exist during that loop, so persisting a value will be difficult. More info on that issue here.

If you use while read ... done < file it will work correctly. Make an exit status flag that defaults to zero, but set it to one if any errors occur. Use it as your script's exit value.

had_errors=0

while read -r output
do
ping -o -c 3 -t 3000 "$output" > /dev/null
if [ $? -eq 0 ]; then
echo "node $output is up"
else
echo "node $output is down"
had_errors=1
fi
done < list.txt

exit $had_errors

How to keep the for loop despite the exit code in if statement

Well, the immediate problem is that you have an exit command in the middle of the loop... which will in fact exit the script when it hits that point. If you don't want it to exit until the loop has finished running, put the exit command after the loop.

But you're also checking whether ssh succeeded in a really weird way. Unless there's something I don't understand involved, just put the ssh command directly in the if condition, and discard its output with >/dev/null 2>&1:

for svr in "${table[@]}"
do
if ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no $svr echo >/dev/null 2>&1
then
echo "Trust is not configured for $svr"
fi
done

exit "$SOME"

Note that I also fixed the reference to ${table[$svr]} (which doesn't make sense), and removed the else clause (which wasn't doing anything). Also, what's $SOME?

EDIT: If you want it to exit if any of the server connections fail, you need to keep track of whether there's been a failure as the loop runs, then use that to control whether it exits at the end.

failures=0
for svr in "${table[@]}"
do
if ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no $svr echo >/dev/null 2>&1
then
echo "Trust is not configured for $svr"
((failures++))
fi
done

if ((failures>0))
then
exit
fi

Bash loop until a certain command stops failing

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

Exit script with error code based on loop operations in bash

Alternative 1

#!/bin/bash

for i in `seq 1 6`; do
if test $i == 4; then
z=1
fi
done
if [[ $z == 1 ]]; then
exit 1
fi

With files

#!/bin/bash

touch ab c d e
for i in a b c d e; do
cat $i
if [[ $? -ne 0 ]]; then
fail=1
fi
done

if [[ $fail == 1 ]]; then
exit 1
fi

The special parameter $? holds the exit value of the last command. A value above 0 represents a failure. So just store that in a variable and check for it after the loop.

The $? parameter actually holds the exit status of the previous pipeline, if present. If the command is killed with a signal then the value of $? will be 128+SIGNAL. For example 128+2 in case of SIGINT (ctrl+c).

Overkill solution with trap

#!/bin/bash

trap ' echo X $FAIL; [[ $FAIL -eq 1 ]] && exit 22 ' EXIT

touch ab c d e
for i in c d e a b; do
cat $i || export FAIL=1
echo F $FAIL
done

While loop in bash: is the loop aware of the exit code for each instruction in the loop?

The while command only checks the exit status of the condition statement immediately following it. It doesn't check the status of the statements inside the loop.

You can use an if statement inside the loop to break out of the loop.

while something
do
command1
if ! command2
then break
fi
command3
done

This will loop as long as something is successful, but stop if command2 fails.

Bash: Loop until command exit status equals 0

Keep it Simple

until nc -z 127.0.0.1 25565
do
echo ...
sleep 1
done

Just let the shell deal with the exit status implicitly

The shell can deal with the exit status (recorded in $?) in two ways, explicit, and implicit.

Explicit: status=$?, which allows for further processing.

Implicit:

For every statement, in your mind, add the word "succeeds" to the command, and then add
if, until or while constructs around them, until the phrase makes sense.

until nc succeeds; do ...; done


The -z option will stop nc from reading stdin, so there's no need for the < /dev/null redirect.



Related Topics



Leave a reply



Submit