if "creation" command fails, sleep 1
while true; do
kubectl get namespace mynamespace && break
kubectl create namespace mynamespace || sleep 1
done
while true; do
kubectl get namespace mynamespace || break
kubectl delete namespace mynamespace || sleep 1
done
nicer errors:
ERR /path/to/file:32 command-that-failed-without-output exited with 1
_on_error() {
trap '' ERR
line_path=$(caller)
line=${line_path% *}
path=${line_path#* }
echo ""
echo "ERR $path:$line $BASH_COMMAND exited with $1"
exit 1
}
trap '_on_error $?' ERR
(
exec ping google.com
) 2>&1 | sed -le "s#^#-- pinger -- #;"
-- pinger -- PING google.com (216.58.209.174): 56 data bytes
-- pinger -- 64 bytes from 216.58.209.174: icmp_seq=0 ttl=58 time=22.026 ms
-- pinger -- 64 bytes from 216.58.209.174: icmp_seq=1 ttl=58 time=21.474 ms
echo "lol" | sed -e "s/.*/hello & world/"
hello lol world
(
colorized-command
) 2>&1 | sed -le 's/\x1b\[[0-9;]*m//g' | sed -le "s#^#-- nocolors -- #;"
_debugger() {
while true; do
printf "\ndebugger> "; read line
[ "$line" = "exit" ] && break
eval "$line" || true
done
}
echo "setting hello"
hello=world
_debugger
start
debugger> echo $hello
world
(
exec command_that_outputs_to_stdout_and_stderr
) >/dev/null 2>&1
_echoerr() {
2>&1 echo "$@"
}
_echoerr "debug messages etc to stderr"
_forever() {
while true; do
eval "$@" && break
sleep 1
done
}
_forever ssh user@host -- uptime
_echoerr "ssh succeeded!"
_never() {
while true; do
eval "$@" || break
sleep 1
done
}
_never ping -c 1 google.com
_echoerr "ping timeout"
echo ${something:-or this}
# or this
something="is now set"
echo ${something:-or this}
# is now set
string="hello==world"
echo ${string%=*}
# hello=
echo ${string%%=*}
# hello
echo ${string#*=}
# =world
echo ${string##*=}
# world
for opt in $@; do
case $opt in
--some-thing=*)
some_thing=${opt#*=}
;;
--other=*)
other=${opt#*=}
;;
*)
echo "unknown opt: $opt"
exit 1
;;
esac
done
without last arg:
opts="${@:1:${#}-1}"
for opt in $opts; do ...
note, after setting ERR trap, set +e
no longer works to prevent trap http://mywiki.wooledge.org/BashFAQ/105
_shutdown() {
# clear traps when already shutting down
trap '' TERM INT ERR
# send kill to entire process tree (including self, that's why ingoring above)
kill 0
# wait for all processes
wait
# unless called new processes can start after trap exits
exit 0
}
trap _shutdown TERM INT ERR
You can only wait once, so store status as a separate associative array
declare -A pids
for greeting in hello hi yo; do
(
sleep 1
echo "$greeting"
) &
pids[$greeting]=$!
done
declare -A statuses
for greeting in "${!pids[@]}"; do
pid=${pids[$greeting]}
set +e
wait $pid
code=$?
set -e
if [ "$code" = "0" ]; then
statuses[$greeting]=ok
else
statuses[$greeting]=fail
fi
done
for greeting in "${!statuses[@]}"; do
status=${statuses[$greeting]}
echo "greeting $greeting was $status"
done
#!/usr/bin/env bash
set -eEuo pipefail
_on_error() {
trap '' ERR
line_path=$(caller)
line=${line_path% *}
path=${line_path#* }
echo ""
echo "ERR $path:$line $BASH_COMMAND exited with $1"
exit 1
}
trap '_on_error $?' ERR
_shutdown() {
# clear traps when already shutting down
trap '' TERM INT ERR
# send kill to entire process tree (including self, that's why ingoring above)
kill 0
# wait for all processes
wait
# unless called new processes can start after trap exits
exit 0
}
trap _shutdown TERM INT
echo "starting /some/process and discarding output ..."
(
exec /some/process
) >/dev/null 2>&1 &
echo "starting /another/process and storing output ..."
(
exec /another/process
) >/tmp/another.log 2>&1 &
echo "starting /yet/another/process and prefixing output ..."
(
exec ping google.com
) 2>&1 | sed -le "s#^#pings: #;" &
echo "now let's hang so that the container stays alive"
tail -f /dev/null & wait