How to start at the same time but exit 1 if any of them fail?
I have the following sh file:
#!/usr/bin/env bash
ecs deploy [some not relevant stuff here] & \
ecs deploy [some not relevant stuff here] & \
ecs deploy [some not relevant stuff here] & \
ecs deploy [some not relevant stuff here] & \
ecs deploy [some not relevant stuff here] & \
ecs deploy [some not relevant stuff here]
This works in part because it runs the deployment commands at the same time, but I have to return the appropriate exit code if any of the deployment completion code is greater than 0.
Is there a way to do this with bash only? If possible, without using any tmp files, just variables.
source to share
It is not clear why you need the largest exit code; without further information, I would assume that you just want to return a non-zero exit code if any of the other processes have a non-zero exit code.
ecs deploy [some not relevant stuff here] & pids+=($!)
ecs deploy [some not relevant stuff here] & pids+=($!)
ecs deploy [some not relevant stuff here] & pids+=($!)
ecs deploy [some not relevant stuff here] & pids+=($!)
ecs deploy [some not relevant stuff here] & pids+=($!)
ecs deploy [some not relevant stuff here] & pids+=($!)
rv=0
for pid in "${pids[@]}"; do
wait "$pid" || rv=1
done
exit "$rv"
source to share
First of all, for managing subprocesses, I would recommend switching to python, as it has several modules that just do it better than anything you can ever write with bash.
There are many OK answers here, but I would do it.
#!/bin/bash
sleep 4; /bin/false &
pids+=("$!")
sleep 5 &
pids+=("$!")
sleep 5 &
pids+=("$!")
sleep 5 &
pids+=("$!")
sleep 5 &
pids+=("$!")
declare -A -g exit_tracker=()
rc=0
for pid in ${pids[@]}; do
wait $pid
if (( $? == 1 )); then
exit_tracker[$pid]="FAIL"
else
exit_tracker[$pid]="SUCCESS"
fi
done
for key in ${!exit_tracker[@]}; do
printf "%s\n" "$key PID STATUS: ${exit_tracker[$key]}"
done
IF YOU WANT TO GET A SPIRITUAL CRYER! ... You can call each return code an associative array and figure out which pid failed. You can add your own names where you see sleep_fail, sleep_pass_1, etc.
#!/bin/bash
declare -A -g pid_names=()
sleep 4; /bin/false &
pid_names["sleep_fail"]="$!"
sleep 5 &
pid_names["sleep_pass_1"]="$!"
sleep 5 &
pid_names["sleep_pass_2"]="$!"
sleep 5 &
pid_names["sleep_pass_3"]="$!"
sleep 5 &
pid_names["sleep_pass_4"]="$!"
declare -A -g exit_tracker=()
rc=0
for pid in ${!pid_names[@]}; do
wait ${pid_names[$pid]}
if (( $? == 1 )); then
exit_tracker[$pid]="FAIL"
else
exit_tracker[$pid]="SUCCESS"
fi
done
for key in ${!exit_tracker[@]}; do
printf "%s\n" "$key PID STATUS: ${exit_tracker[$key]}"
done
The output from the above would look like this:
dumbledore@ansible1a [OPS]:~ > bash test.sh
sleep_fail PID STATUS: FAIL
sleep_pass_4 PID STATUS: SUCCESS
sleep_pass_2 PID STATUS: SUCCESS
sleep_pass_3 PID STATUS: SUCCESS
sleep_pass_1 PID STATUS: SUCCESS
source to share
# note normal single quotes in following line
CMD='curl -I shoudfail.com'
# run the command, and log it IF IT FAILS
( $CMD || echo $CMD >> tmpout ) &
# rinse, lather, repeat
CMD='curl -I somecmdthatwillfail.com'
# run the command, and log it IF IT FAILS
( $CMD || echo $CMD >> tmpout ) &
...
while [ ! -z `jobs` ]
do
sleep 5
done
If you are using readline to populate the CMD rather than literals in your code, then you can use the output of one iteration as input to the next.
source to share
#!/usr/bin/env bash
# This array will store process ID of background processes
declare -a pid
# Run curl and save add its pid to array
curl -I shoudfail.com; echo $? >> tmpout &
pid+=( $! )
# Run another curl and save add its pid to array
curl -I somecmdthatwillfail.com a; echo $? >> tmpout & \
pid+=( $! )
# Run a third curl and save add its pid to array
curl -I google.com; echo $? >> tmpout;
pid+=( $! )
# Wait for all background processes to stop
wait
# Loop through array of pids
for proc in "${pid[@]}"; do
# Get return value of process from wait
wait "$proc"
retval=$?
# Replace maxret if the return value is larger
[ "$retval" -gt "$maxret" ] && maxret="$retval"
done
echo "$maxret"
source to share