Skip to content

Instantly share code, notes, and snippets.

@darko-mesaros
Created March 12, 2026 20:24
Show Gist options
  • Select an option

  • Save darko-mesaros/f02667075735393f87c232016c491226 to your computer and use it in GitHub Desktop.

Select an option

Save darko-mesaros/f02667075735393f87c232016c491226 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# waddlesay - an ASCII duck that says things, wrapped in an HTML comment
# Usage: waddlesay "Your message here"
# echo "piped message" | ducksay
# waddlesay -w 40 "message" (set max visual width)
set -euo pipefail
MAX_WIDTH=40
# ── Parse flags ─────────────────────────────────────────────
while getopts "w:" opt; do
case $opt in
w) MAX_WIDTH="$OPTARG" ;;
*) echo "Usage: ducksay [-w width] <message>" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
# ── Read input ──────────────────────────────────────────────
if [[ $# -gt 0 ]]; then
msg="$*"
else
msg="$(cat)"
fi
msg="$(echo "$msg" | xargs)"
if [[ -z "$msg" ]]; then
echo "Usage: ducksay [-w width] <message>" >&2
exit 1
fi
# ── Word wrap (max 2 lines) ────────────────────────────────
wrap() {
local width=$1
lines=()
if (( ${#msg} <= width )); then
lines+=("$msg")
return
fi
# Find last space within width
local chunk="${msg:0:$width}"
local cut=-1
for (( i=${#chunk}-1; i>=0; i-- )); do
if [[ "${chunk:$i:1}" == " " ]]; then
cut=$i
break
fi
done
if (( cut == -1 )); then
lines+=("${msg:0:$width}")
lines+=("${msg:$width}")
else
lines+=("${msg:0:$cut}")
lines+=("${msg:$((cut + 1))}")
fi
}
# ── Build the duck ──────────────────────────────────────────
build() {
local n=${#lines[@]}
if (( n == 1 )); then
echo '<!-- _'
echo " .__( .)< (${lines[0]})"
echo ' \___)'
echo '~~~~~~~~~~~~~~~~~-->'
else
local max_len=${#lines[0]}
(( ${#lines[1]} > max_len )) && max_len=${#lines[1]}
local p1 p2
printf -v p1 "%-${max_len}s" "${lines[0]}"
printf -v p2 "%-${max_len}s" "${lines[1]}"
echo '<!-- _'
echo " .__( .)< (${p1})"
echo " \\___) . (${p2})"
echo '~~~~~~~~~~~~~~~~~-->'
fi
}
# ── Main ────────────────────────────────────────────────────
wrap "$MAX_WIDTH"
if (( ${#lines[@]} > 2 )); then
echo "Error: message too long to fit in 2 lines at width ${MAX_WIDTH}" >&2
echo "Tip: use -w with a larger width" >&2
exit 1
fi
build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment