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 addif
, 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
Gdb Can Not Open Shared Object File
Pseudo-Random Stack Pointer Under Linux
How to Receive the Wrong Ethernet Frames and Disable the Crc/Fcs Calcul
Webpack --Watch Exits After Building Once
Hardware Acceleration Without X
Print on Terminal and into File Simultaneously
Service Doesn't Support Chkconfig
Get Rid of "Gcc - /Usr/Bin/Ld: Warning Lib Not Found"
Running Docker on Ubuntu: Mounted Host Volume Is Not Writable from Container
Docker Not Responding to Ctrl+C in Terminal
Dynamic Loading and Weak Symbol Resolution
How to Get the Exit Status a Loop in Bash
Can Inode and Crtime Be Used as a Unique File Identifier
Deceive the Jvm About the Number of Available Cores (On Linux)