tegarri tegarri - 4 months ago 27
Bash Question

How to list all zsh autocompletions?

In zsh, I'm trying to get an idea of which commands have an existing completion so that I can write completions for commands that don't.

Is there a way to list the commands that zsh will complete without grepping the completion files? For instance, is there a built-in command that will list them?


The list of known completions is stored in the associative array _comps. The command names and other completion contexts are used as keys for _comps, while the corresponding completion functions are stored as values.

You can get a full list of commands with associated completions with the following command:

for command completion in ${(kv)_comps:#-*(-|-,*)}
    printf "%-32s %s\n" $command $completion
done | sort


  • for command completion in LIST; COMMAND takes iterates over LIST while taking two elements, command and completion, on every iteration and running COMMAND for them. This is also a short form of the for-loop that does not require do and done.
  • ${(kv)ASSOC_ARRAY} expands the associative array ASSOC_ARRAY to a space separated list of key-value pairs. So it is an alternating list of "key1 value1 key2 value2 key3 value3 …", which is taken up by the two arguments of the for-loop. $ASSOC_ARRAY would only expand to a list of values.
  • ${ASSOC_ARRAY:#PATTERN} filters out all elements of ASSOC_ARRAY from its expansion, where the key matches PATTERN.
  • The pattern -*(-|-,*) matches the names of all special contexts, like -math-, -parameter- or -value-,NAME,COMMAND. It would also filter any command name that either matches -*- or -*-,*, should such a command have a completion on your system. (You could just leave out the pattern filter to be sure)
  • printf "%-32s %s\n" $command $completion does a formatted output so that you get a nice table. $command is printed in place of %-32s, padded to 32 characters with left-alignment (-). $completion is printed in place of %s.
  • | sort: associative arrays are unordered, so output of the loop needs to be run through sort in order to get a ordered list.