Adding some k8s related tools
This commit is contained in:
parent
727bd2b882
commit
c6022128ec
|
@ -0,0 +1,70 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
if [[ "$0" == "$SHELL" ]]; then
|
||||||
|
|
||||||
|
if [[ -z "FIX_KUBECTL_RECALL" ]]; then
|
||||||
|
unset kubectl 2>/dev/null || unalias kubectl 2>/dev/null || true
|
||||||
|
|
||||||
|
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ 'function' == $(type -t kubectl-fix) ]] && unset kubectl-fix
|
||||||
|
|
||||||
|
[[ ! -r "$HOME/.kube/config" ]] \
|
||||||
|
|| export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config}"
|
||||||
|
|
||||||
|
if [[ -n "$(type -t 'k3s')" && -z "$(type -t 'kubectl')" ]]; then
|
||||||
|
if [[ -r "${KUBECONFIG}" ]]; then
|
||||||
|
kubectl() { k3s kubectl "${@}"; }
|
||||||
|
elif [[ -n "${KUBECONFIG}" && -e "${KUBECONFIG}" ]]; then
|
||||||
|
eval "
|
||||||
|
kubectl-fix() {
|
||||||
|
mkdir \"$HOME/.kube\" -p
|
||||||
|
if [[ -e \"\${KUBECONFIG}\" && ! -r \"$HOME/.kube/config\" ]]; then
|
||||||
|
sudo install --mod 600 --owner \"$USER\" \"\${KUBECONFIG}\" \"$HOME/.kube/config\"
|
||||||
|
unset KUBECONFIG
|
||||||
|
fi
|
||||||
|
FIX_KUBECTL_RECALL=1 . \"$BASH_SOURCE\"
|
||||||
|
}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$(type -t 'kubectl')" ]]; then
|
||||||
|
|
||||||
|
. <( kubectl completion ${SHELL##*/} )
|
||||||
|
|
||||||
|
if [[ -n "$(type -t 'kubectl-cnpg')" ]]; then
|
||||||
|
. <( kubectl cnpg completion ${SHELL##*/} )
|
||||||
|
else
|
||||||
|
CNPG_VER="${CNPG_VER:-1.20.2}"
|
||||||
|
GH_URL=https://github.com/cloudnative-pg/cloudnative-pg
|
||||||
|
DEB_FILE="kubectl-cnpg_${CNPG_VER}_linux_x86_64.deb"
|
||||||
|
URL=${GH_URL}/releases/download/v${CNPG_VER}/${DEB_FILE}
|
||||||
|
printf '%s\n' \
|
||||||
|
'To download adn install cnpg kubectl plugin, run:' \
|
||||||
|
" wget ${URL}" \
|
||||||
|
" sudo dpkg -i $DEB_FILE"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$(type -t 'k3s')" ]]; then
|
||||||
|
. <( k3s completion ${SHELL##*/} )
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$(type -t 'helm')" ]]; then
|
||||||
|
. <( helm completion ${SHELL##*/} 2>/dev/null )
|
||||||
|
fi
|
||||||
|
|
||||||
|
kg() {
|
||||||
|
kubectl get ${NS:+--namespace=}${NS:---all-namespaces} "${@}" | { sed -u 1q; sort; }
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
elif [[ "$1" == '-' ]]; then
|
||||||
|
cat $0
|
||||||
|
else
|
||||||
|
SCRIPT_NAME="$(basename $0)"
|
||||||
|
printf '%s\n' \
|
||||||
|
"It seems $SCRIPT_NAME was invoked as a script. It should be sourced instead." \
|
||||||
|
'The easiest way is to call it like this:' \
|
||||||
|
" $ . <( $SCRIPT_NAME - ) # Note the '-' after the script's name" \
|
||||||
|
''
|
||||||
|
fi
|
|
@ -0,0 +1,135 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
USER_HOME=$HOME
|
||||||
|
[[ -n "${SUDO_USER}" ]] && USER_HOME="$(eval "echo ~${SUDO_USER}")"
|
||||||
|
. ${SHRC_D:-$SCRIPT_DIR}/01_util.functions
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
JSON=0
|
||||||
|
if [[ " $* " =~ " --help " ]]; then
|
||||||
|
cat <<USAGE
|
||||||
|
Usage:
|
||||||
|
./kube-get-secrets.sh --help
|
||||||
|
sudo ./kube-get-secrets.sh [--json]
|
||||||
|
|
||||||
|
Description:
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARGS=()
|
||||||
|
ARGS_MODE=1
|
||||||
|
ALL=0
|
||||||
|
while [[ -n "$1" ]]; do
|
||||||
|
if [[ "$ARGS_MODE" -eq 1 && "$1" =~ ^-- ]]; then
|
||||||
|
case "$1" in
|
||||||
|
"--json")
|
||||||
|
JSON=1
|
||||||
|
;;
|
||||||
|
"--force")
|
||||||
|
ALL=1
|
||||||
|
;;
|
||||||
|
"--")
|
||||||
|
ARGS_MODE='--'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
ARGS=("${ARGS[@]}" "$1")
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
ARGS=("${ARGS[@]}" "$1")
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# require_root
|
||||||
|
|
||||||
|
QUERY_NAMESPACE=' -A'
|
||||||
|
[[ ${#ARGS[@]} -eq 0 ]] || QUERY_NAMESPACE=$( printf -- ' --namespace=ix-%s' "${ARGS[@]}" )
|
||||||
|
|
||||||
|
jqcode='
|
||||||
|
.items[] | select(.metadata.name|test("."))
|
||||||
|
| {
|
||||||
|
"name": .metadata.namespace,
|
||||||
|
"app": (
|
||||||
|
if .metadata.labels."app.kubernetes.io/instance" != null then
|
||||||
|
.metadata.labels."app.kubernetes.io/instance"
|
||||||
|
else
|
||||||
|
.metadata.labels."cnpg.io/cluster"
|
||||||
|
end
|
||||||
|
),
|
||||||
|
,"data":
|
||||||
|
,"raw": .
|
||||||
|
} | {
|
||||||
|
"name": .name,
|
||||||
|
"app": .app,
|
||||||
|
"url": (
|
||||||
|
if (.url|type) == "object" then
|
||||||
|
""
|
||||||
|
else
|
||||||
|
.url
|
||||||
|
end
|
||||||
|
),
|
||||||
|
"data": (
|
||||||
|
if (.url|type) == "object" then
|
||||||
|
.url
|
||||||
|
else
|
||||||
|
.url |
|
||||||
|
match("(.*)://(.+):(.+)@([^:]+)(:(\\d+))?/(.*)$") | .captures | {
|
||||||
|
"protocol": .[0].string,
|
||||||
|
"username": .[1].string,
|
||||||
|
"password": .[2].string,
|
||||||
|
"passwordlen": .[2].string | length,
|
||||||
|
"host": .[3].string,
|
||||||
|
"safeport": .[4].string,
|
||||||
|
"port": .[5].string,
|
||||||
|
"dbname": .[6].string,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
)
|
||||||
|
} | {
|
||||||
|
"name": .name,
|
||||||
|
"raw_url": .url,
|
||||||
|
"url": "\(.data.protocol)://\(.data.username)@\(.data.password):\(.data.host).\(.name).svc.cluster.local\(.data.safeport)/\(.data.dbname)",
|
||||||
|
"safeurl": "\(.data.protocol)://\(.data.username)@*******:\(.data.host).\(.name).svc.cluster.local\(.data.safeport)/\(.data.dbname)",
|
||||||
|
"protocol": .data.protocol,
|
||||||
|
"username": .data.username,
|
||||||
|
"password": .data.password,
|
||||||
|
"pwd_len": .data.passwordlen,
|
||||||
|
"host": "\(.data.host).\(.name).svc.cluster.local",
|
||||||
|
"port": .data.port,
|
||||||
|
"dbname": .data.dbname
|
||||||
|
}
|
||||||
|
'
|
||||||
|
|
||||||
|
[[ "$ALL" -eq 1 ]] || jqcode="$jqcode | select( .raw_url != \"\" )"
|
||||||
|
|
||||||
|
json_results="$(
|
||||||
|
<<<"${QUERY_NAMESPACE}" \
|
||||||
|
xargs -n1 k3s kubectl \
|
||||||
|
get secrets \
|
||||||
|
--output json \
|
||||||
|
| jq "$jqcode"
|
||||||
|
)"
|
||||||
|
|
||||||
|
[[ "$JSON" -eq 1 ]] && echo "$json_results" && exit 0
|
||||||
|
|
||||||
|
JQ_COLS="[$( <<<"\"$TCDBCOLS\"" \
|
||||||
|
jq -r '. | split(",") | map( "\"\(.)\"" ) | join(",")'
|
||||||
|
)]"
|
||||||
|
JQ_COLS_REGEX="$( <<<"$JQ_COLS" \
|
||||||
|
jq -r '. | map ( ".\(.)" ) | join(",")'
|
||||||
|
)"
|
||||||
|
|
||||||
|
[[ -z "$NOHEAD" ]] || JQ_COLS=
|
||||||
|
|
||||||
|
jqcode='
|
||||||
|
['"${JQ_COLS^^}"'] + [.[] |
|
||||||
|
['"$JQ_COLS_REGEX"']
|
||||||
|
] | .[] | join("|")
|
||||||
|
'
|
||||||
|
|
||||||
|
<<<"$json_results" jq -s '.' | jq -r "$jqcode" | column -t -s "|"
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,268 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
# [LICENSE: GPL3](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
|
# Author: [Lockszmith](https://stackexchange.com/users/421248/lockszmith) 2023-10(Oct)-08
|
||||||
|
|
||||||
|
set -e
|
||||||
|
eval "$SETX"
|
||||||
|
|
||||||
|
ZELLIJ_PATH="${ZELLIJ_PATH:-$(which zellij)}" || true
|
||||||
|
|
||||||
|
NOZELLIJ=${NOZELLIJ:-$NOWATCH}
|
||||||
|
NOWATCH=${NOWATCH:-$NOZELLIJ}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if [[ -n "${ZELLIJ_PATH}" && -x "${ZELLIJ_PATH}" && -z "$NOZELLIJ" ]]; then
|
||||||
|
printf "Starting zellij layout..." >&2
|
||||||
|
$ZELLIJ_PATH ${INTAB:+action new-tab} --layout <(
|
||||||
|
get_zellij_layout
|
||||||
|
# ZELLIJ_PATH="$ZELLIJ_PATH" APP="$APP" NS="$NS" TAIL="$TAIL" \
|
||||||
|
# envsubst < ~/watch-k3s-app.kdl
|
||||||
|
)
|
||||||
|
else
|
||||||
|
unset ZELLIJ_PATH
|
||||||
|
export NOZELLIJ=1 APP="$APP"
|
||||||
|
$0 -- "charts"
|
||||||
|
$0 -- "pvc"
|
||||||
|
$0 -- "apps"
|
||||||
|
$0 -- "services"
|
||||||
|
$0 -- "events"
|
||||||
|
$0 -- "pods"
|
||||||
|
$0 -- "cnpg"
|
||||||
|
$0 -- "logs"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_zellij_layout() {
|
||||||
|
cat - <<ZELLIJ_LAYOUT
|
||||||
|
layout {
|
||||||
|
pane_template name="watch_k3s_app" {
|
||||||
|
command "$HOME/bin/watch-k3s-app"
|
||||||
|
}
|
||||||
|
pane_template name="charts" {
|
||||||
|
watch_k3s_app name="CHARTS" size=5 {
|
||||||
|
args "--" "charts" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="pvc" {
|
||||||
|
watch_k3s_app name="PERSISTENT VOLUME CLAIMS (PVC)" size=9 {
|
||||||
|
args "--" "pvc" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pane_template name="apps" {
|
||||||
|
watch_k3s_app name="DEPLOYMENT.APPS" {
|
||||||
|
args "--" "apps" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="services" {
|
||||||
|
watch_k3s_app name="SERVICES" size=9 {
|
||||||
|
args "--" "services" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="services_and_apps" {
|
||||||
|
pane split_direction="vertical" {
|
||||||
|
apps size="35%"
|
||||||
|
services
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="events" {
|
||||||
|
watch_k3s_app name="EVENTS" size=9 {
|
||||||
|
args "--" "events" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="pods" {
|
||||||
|
watch_k3s_app name="PODS" {
|
||||||
|
args "--" "pods" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="pods_and_events" {
|
||||||
|
pane split_direction="vertical" {
|
||||||
|
pods size="40%"
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pane_template name="logs" {
|
||||||
|
watch_k3s_app name="LOGS ${APP}" {
|
||||||
|
args "--" "logs" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="cnpg" {
|
||||||
|
watch_k3s_app name="CLOUDNATIVE POSTGRESQL" size=9 {
|
||||||
|
args "--" "cnpg" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pane_template name="logs_and_cnpg" {
|
||||||
|
pane split_direction="vertical" {
|
||||||
|
logs size="65%"
|
||||||
|
cnpg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pane split_direction="horizontal" {
|
||||||
|
pane size=1 command="printf" borderless=true {
|
||||||
|
args "### Watching kubernetes environment ${NS} --- [Ctrl+x] to close | [mouse-click]+[F11] Expand Pane | [Ctrl-C]+[Enter] to refersh"
|
||||||
|
}
|
||||||
|
// pane stacked=true {
|
||||||
|
charts
|
||||||
|
pvc
|
||||||
|
// }
|
||||||
|
|
||||||
|
services_and_apps
|
||||||
|
pods_and_events
|
||||||
|
logs_and_cnpg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keybinds {
|
||||||
|
shared {
|
||||||
|
bind "Ctrl x" { CloseTab; }
|
||||||
|
bind "F11" { ToggleFocusFullscreen; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pane_frames true
|
||||||
|
|
||||||
|
ZELLIJ_LAYOUT
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat_out() {
|
||||||
|
dd if=/dev/zero bs=${2:-10} count=1 2>/dev/null | tr '\0' "${1:?Repeat character missing}"
|
||||||
|
}
|
||||||
|
visual_sleep() {
|
||||||
|
local SLEEP=$(( 0 + ${1:-2} )) MSG="${MSG:-Restarting in %s %s}"
|
||||||
|
tput sc;
|
||||||
|
while (( SLEEP > 0 )); do
|
||||||
|
tput el; printf "$MSG" "${SLEEP}s" "$(repeat_out . ${SLEEP})"
|
||||||
|
sleep 1s
|
||||||
|
tput rc 1; tput el;
|
||||||
|
(( SLEEP-=1 )) || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$1" == "--" ]] || APP=${APP:-${1}}
|
||||||
|
NS=${APP:+--namespace=ix-}${APP:---all-namespaces}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"--help")
|
||||||
|
cat - <<USAGE
|
||||||
|
Watch k3s apps (with zellij support) for TrueChart Apps on TrueNAS SCALE
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
$(basename $0) [Installed App Name]
|
||||||
|
$(basename $0) -- <output type> [<Set Expression1> [<Set Expression...>]]
|
||||||
|
|
||||||
|
Invokation modifiers (environment variable):
|
||||||
|
[NOREPEAT=1] [NOWATCH=1] [SLEEP=3] $(basename $0) ...
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This script will pull from k3s the follwing:
|
||||||
|
charts (helm charts)
|
||||||
|
pvc
|
||||||
|
apps (deployment.apps)
|
||||||
|
services
|
||||||
|
events
|
||||||
|
pods
|
||||||
|
cnpg status (applicable for APP only)
|
||||||
|
contianer-logs (applicable for APP only)
|
||||||
|
|
||||||
|
By default, if zellij exists, it will WATCH all of these for
|
||||||
|
changes in parallel.
|
||||||
|
If zellij doesn't exist, it will list all, SLEEP for a few seconds,
|
||||||
|
then REPEAT.
|
||||||
|
|
||||||
|
To produce output to share in bug reports, calling with
|
||||||
|
NOREPEAT=1 NOWATCH=1 ...
|
||||||
|
will output all the details and exit.
|
||||||
|
|
||||||
|
If an APP is specified, output is confined to the specific
|
||||||
|
namespace and service. Otherwise, it will output information about
|
||||||
|
k3s all-namespaces.
|
||||||
|
|
||||||
|
* For cnpg status, the cnpg plugin needs to be installed.
|
||||||
|
On TrueNAS SCALE, this install might be required after a reboot.
|
||||||
|
|
||||||
|
Zellij specific support
|
||||||
|
When zellij exists and running, zellij will create a set of panes
|
||||||
|
with the above list of views watching for changes in parallel.
|
||||||
|
|
||||||
|
It maps <Ctrl>-<X> as the exit key.
|
||||||
|
and it maps <F11> as a Full-Screen toggle, to use it you need to
|
||||||
|
select inside a pane with a mouse, and then click the key.
|
||||||
|
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
;;
|
||||||
|
"--")
|
||||||
|
eval "${*:3}"
|
||||||
|
export KUBECONFIG
|
||||||
|
K_WATCH="${ZELLIJ_PATH:+--watch-only --no-headers}"
|
||||||
|
C_WATCH="watch -tcn4"
|
||||||
|
[[ -z "$NOZELLIJ" && -z "$NOWATCH" ]] || { K_WATCH=''; C_WATCH='eval'; }
|
||||||
|
|
||||||
|
|
||||||
|
case "$2" in
|
||||||
|
"charts")
|
||||||
|
${C_WATCH} "helm list ${NS} | sort"
|
||||||
|
;;
|
||||||
|
"pvc")
|
||||||
|
k3s kubectl get pvc ${NS} --sort-by='.metadata.creationTimestamp'
|
||||||
|
[[ -z "${K_WATCH}" ]] || k3s kubectl get pvc ${NS} ${K_WATCH}
|
||||||
|
;;
|
||||||
|
"apps")
|
||||||
|
k3s kubectl get deployment.apps ${NS} --sort-by='.metadata.creationTimestamp'
|
||||||
|
[[ -z "${K_WATCH}" ]] || k3s kubectl get deployment.apps ${NS} ${K_WATCH}
|
||||||
|
;;
|
||||||
|
"services")
|
||||||
|
k3s kubectl get services ${NS} --sort-by='.metadata.creationTimestamp'
|
||||||
|
[[ -z "${K_WATCH}" ]] || k3s kubectl get services ${NS} ${K_WATCH}
|
||||||
|
;;
|
||||||
|
"events")
|
||||||
|
k3s kubectl get events ${NS} --sort-by='.metadata.creationTimestamp'
|
||||||
|
[[ -z "${K_WATCH}" ]] || k3s kubectl get events ${NS} ${K_WATCH} \
|
||||||
|
;;
|
||||||
|
"pods")
|
||||||
|
k3s kubectl get pods ${NS} --sort-by='.metadata.creationTimestamp'
|
||||||
|
[[ -z "${K_WATCH}" ]] || k3s kubectl get pods ${NS} \
|
||||||
|
${K_WATCH};
|
||||||
|
;;
|
||||||
|
"cnpg")
|
||||||
|
sleep 0.4s;
|
||||||
|
[[ -n "${APP}" ]] \
|
||||||
|
&& ${C_WATCH} "k3s kubectl cnpg status ${NS} ${APP}-cnpg-main" \
|
||||||
|
|| k3s kubectl get clusters.postgresql.cnpg.io ${NS} ${K_WATCH}
|
||||||
|
;;
|
||||||
|
"logs")
|
||||||
|
MSG='N/A with --all-namespaces'
|
||||||
|
if [[ -n "${APP}" ]]; then
|
||||||
|
MSG="no pods active for $APP"
|
||||||
|
APP=($(k3s kubectl get pods ${NS} --output name | grep -E "^pod/$APP(-[^-]+){2}$"))
|
||||||
|
|
||||||
|
FOLLOW='--follow'
|
||||||
|
[[ -z "$NOWATCH" ]] || { FOLLOW=''; TAIL=${TAIL:-40}; }
|
||||||
|
|
||||||
|
while ! k3s kubectl logs ${NS} ${FOLLOW} ${TAIL:+--tail=${TAIL}} \
|
||||||
|
"${APP}"; do
|
||||||
|
printf 'could not load logs, checking for previous logs...\n'
|
||||||
|
k3s kubectl logs ${NS} -p ${TAIL:+--tail=${TAIL}} "${APP}" \
|
||||||
|
|| printf "${MSG}"
|
||||||
|
|
||||||
|
[[ -z "$NOWATCH" ]] || break;
|
||||||
|
visual_sleep ${SLEEP:-3}
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "Don't know how to handle $2\n" 1>&2;
|
||||||
|
false;
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
while main "$1" && [[ -z "$NOREPEAT" ]]; do
|
||||||
|
tput cuu1;
|
||||||
|
visual_sleep ${SLEEP:-3}
|
||||||
|
done
|
||||||
|
esac
|
||||||
|
|
Loading…
Reference in New Issue