151 lines
3.3 KiB
Bash
151 lines
3.3 KiB
Bash
#!/usr/bin/env sh
|
|
#
|
|
# Compare a command exit status to some given number(s) for a period of time.
|
|
|
|
CMD_NAME="${0##*/}"
|
|
CMD=""
|
|
STATUS=0
|
|
TIME=10
|
|
TIME_START=0
|
|
QUIET=0
|
|
EXIT_STATUS=1
|
|
|
|
usage() {
|
|
cat << EOF >&2
|
|
Usage: ${CMD_NAME} [-c 'COMMAND']
|
|
${CMD_NAME} [OPTION]... [-c 'COMMAND']
|
|
${CMD_NAME} [-c 'COMMAND'] [OPTION]...
|
|
|
|
${CMD_NAME} compares a command exit status to some given number(s)
|
|
for a period of time. If comparison is successfully
|
|
${CMD_NAME} returns 0, otherwise 1.
|
|
|
|
Example: ${CMD_NAME} -c 'echo > /dev/tcp/127.0.0.1/5432'
|
|
${CMD_NAME} -s 0 57 -c 'curl 127.0.0.1:5432'
|
|
${CMD_NAME} -c 'nc -z 127.0.0.1 5432' -s 0 -t 20 -q
|
|
|
|
Options:
|
|
-c, --command ['COMMAND'] execute a COMMAND.
|
|
-s, --status [NUMBER]... target exit status of COMMAND, default 0.
|
|
-t, --time [NUMBER] max time to wait in seconds, default 10.
|
|
-q, --quiet do not make any output, default false.
|
|
--help display this help.
|
|
|
|
Notice that quotes are needed after -c/--command for multi-argument
|
|
COMMANDs.
|
|
|
|
Specifying a same OPTION more than once overrides the previews.
|
|
So "${CMD_NAME} -c 'nothing' -c 'curl 127.0.0.1:5432'" will be
|
|
the same as "${CMD_NAME} -c 'curl 127.0.0.1:5432'".
|
|
It does not apply to option -q/--quiet.
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
output() {
|
|
if [ "${QUIET}" -ne 1 ]; then
|
|
printf "%s\n" "$*" 1>&2;
|
|
fi
|
|
}
|
|
|
|
process_command() {
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
-c | --command)
|
|
# allow one shift when no arguments
|
|
if [ -n "$2" ]; then
|
|
CMD="$2"
|
|
shift 1
|
|
fi
|
|
shift 1
|
|
;;
|
|
-s | --status)
|
|
# ensure that a number is provided
|
|
if ([ "$2" -eq "$2" ]) >/dev/null 2>&1; then
|
|
unset STATUS
|
|
# ensure that a number is provided
|
|
while ([ "$2" -eq "$2" ]) >/dev/null 2>&1; do
|
|
if [ -z "${STATUS}" ]; then
|
|
STATUS="$2"
|
|
shift 1
|
|
else
|
|
STATUS="${STATUS} $2"
|
|
shift 1
|
|
fi
|
|
done
|
|
fi
|
|
shift 1
|
|
;;
|
|
-t | --time)
|
|
# ensure that a number is provided
|
|
if ([ "$2" -eq "$2" ]) >/dev/null 2>&1; then
|
|
TIME="$2"
|
|
shift 1
|
|
fi
|
|
shift 1
|
|
;;
|
|
-q | --quiet)
|
|
QUIET=1
|
|
shift 1
|
|
;;
|
|
--help)
|
|
usage
|
|
;;
|
|
*)
|
|
output "Unknown argument: $1"
|
|
output "Try '${CMD_NAME} --help' for more information."
|
|
exit "${EXIT_STATUS}"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "${CMD}" ]; then
|
|
output "Missing command: -c, --command ['COMMAND']"
|
|
output "Try '${CMD_NAME} --help' for more information."
|
|
exit "${EXIT_STATUS}"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
message="failed"
|
|
|
|
process_command "$@"
|
|
|
|
TIME_START=$(date +%s)
|
|
|
|
while [ $(($(date +%s)-TIME_START)) -lt "${TIME}" ]; do
|
|
|
|
($CMD) >/dev/null 2>&1 &
|
|
pid="$!"
|
|
|
|
# while both ps and time are running sleep 1s
|
|
while kill -0 "${pid}" >/dev/null 2>&1 &&
|
|
[ $(($(date +%s)-TIME_START)) -lt "${TIME}" ]; do
|
|
sleep 1
|
|
done
|
|
|
|
# gets CMD status
|
|
kill "${pid}" >/dev/null 2>&1
|
|
wait "${pid}" >/dev/null 2>&1
|
|
cmd_exit_status="$?"
|
|
|
|
# looks for equlity in CMD exit status and one of the given status
|
|
for i in $STATUS; do
|
|
if ([ "${cmd_exit_status}" -eq "${i}" ]) >/dev/null 2>&1; then
|
|
message="finished successfully"
|
|
EXIT_STATUS=0
|
|
break 2
|
|
fi
|
|
done
|
|
|
|
done
|
|
|
|
output "${CMD_NAME} ${message} after $(($(date +%s)-TIME_START)) second(s)."
|
|
output "cmd: ${CMD}"
|
|
output "target exit status: ${STATUS}"
|
|
output "exited status: ${cmd_exit_status}"
|
|
|
|
exit "${EXIT_STATUS}"
|
|
}
|
|
|
|
main "$@" |