Skip to content

Instantly share code, notes, and snippets.

@giladbarnea
Created March 22, 2026 13:28
Show Gist options
  • Select an option

  • Save giladbarnea/ff6c1b08d062d8d680f88181ade33bc7 to your computer and use it in GitHub Desktop.

Select an option

Save giladbarnea/ff6c1b08d062d8d680f88181ade33bc7 to your computer and use it in GitHub Desktop.
helpall | recursive subcommand help printer
#!/usr/bin/env zsh
set -euo pipefail
if (( $# < 1 )); then
print -u2 "Usage: helpall <command> [fixed-arg ...]"
exit 1
fi
typeset -a root_argv
root_argv=("$@")
root_command="${(j: :)root_argv}"
help_timeout="${HELPALL_TIMEOUT:-5}"
if ! command -v -- "$root_argv[1]" >/dev/null 2>&1; then
print -u2 "helpall: command not found: $root_argv[1]"
exit 1
fi
typeset -a queue
typeset -A seen
queue=("$root_command")
seen[$root_command]=1
extract_subcommands() {
local current="$1"
local help_text
help_text="$(cat)"
local normalized_help_text
normalized_help_text="$(printf '%s\n' "$help_text" | perl -pe 's/.\x08//g')"
local command_blocks
command_blocks="$(
printf '%s\n' "$normalized_help_text" \
| awk '
/^[A-Z][A-Z ]*COMMANDS$|^AVAILABLE COMMANDS$|^Commands:$/ {in_block=1; next}
in_block && /^[^[:space:]]/ {in_block=0}
in_block {print}
'
)"
local subcommand_blocks
subcommand_blocks="$(
printf '%s\n' "$normalized_help_text" \
| awk '
/^Subcommands:$/ {in_block=1; next}
in_block && /^[^[:space:]]/ {in_block=0}
in_block {print}
'
)"
{
printf '%s\n' "$normalized_help_text" | grep -Po '^\h{2,}\K[[:alnum:]_][[:alnum:]_.-]*(?=\h{2,})'
printf '%s\n' "$command_blocks" | grep -Po '^\h{2,}\K[[:alnum:]_][[:alnum:]_.-]*(?=:\h{2,}|\h{2,})'
printf '%s\n' "$subcommand_blocks" | grep -Po '^\h*-\h+\K[[:alnum:]_][[:alnum:]_.-]*(?=:\h)'
printf '%s\n' "$normalized_help_text" | grep -Po "^\h*(?:[Uu]sage:|or:)\h+\Q${current}\E\h+\K[[:alnum:]_][[:alnum:]_.-]*(?=\h|$)"
printf '%s\n' "$normalized_help_text" | grep -Po "^\h*(?:[Uu]sage:|or:)\h+\Q${current}\E\h+\[\K[[:alnum:]_][[:alnum:]_.-]*(?=\h|\])"
printf '%s\n' "$normalized_help_text" | grep -Po "^\h+\Q${current}\E\h+\K[[:alnum:]_][[:alnum:]_.-]*(?=\h|$)"
printf '%s\n' "$normalized_help_text" | grep -Po "^\h+\Q${current}\E\h+\[\K[[:alnum:]_][[:alnum:]_.-]*(?=\h|\])"
} \
| grep -Pv '^(help|or|usage)$' \
| grep -Pvi '^(flags|options|command|subcommand|arguments|args)$' \
| grep -Pv '^[A-Z][A-Z0-9_-]*$' \
| awk '!seen[$0]++' || true
}
run_help() {
local -a cmd_argv
cmd_argv=("$@")
local output
if output="$(perl -e 'alarm shift; exec @ARGV' "$help_timeout" "${cmd_argv[@]}" --help 2>&1)"; then
:
else
local exit_code=$?
output+=$'\n'
output+="[helpall] command exited non-zero while printing help (exit=$exit_code)"
fi
printf '%s' "$output"
}
run_short_help() {
local -a cmd_argv
cmd_argv=("$@")
local output
if output="$(perl -e 'alarm shift; exec @ARGV' "$help_timeout" "${cmd_argv[@]}" -h 2>&1)"; then
printf '%s' "$output"
fi
}
integer index=1
while (( index <= ${#queue[@]} )); do
current="${queue[index]}"
(( index++ ))
label="$current"
typeset -a current_argv children
current_argv=(${=current})
help_output="$(run_help "${current_argv[@]}")"
printf '★ ───────────[ %s ]───────────\n\n' "$label"
printf '%s\n' "$help_output"
printf '\n'
children=("${(@f)$(printf '%s\n' "$help_output" | extract_subcommands "$label")}")
if (( ${#children[@]} == 0 )) && [[ "$help_output" == *$'\b'* ]]; then
short_help_output="$(run_short_help "${current_argv[@]}")"
if [[ -n "$short_help_output" ]]; then
children=("${(@f)$(printf '%s\n' "$short_help_output" | extract_subcommands "$label")}")
fi
fi
for child in "${children[@]}"; do
if [[ -z "$child" ]]; then
continue
fi
next_command="$current $child"
if [[ -n "${seen[$next_command]-}" ]]; then
continue
fi
seen[$next_command]=1
queue+=("$next_command")
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment