Linux/Unix: Finding all commands on the system

📄 Wiki page | 🕑 Last updated: Dec 23, 2022

I recently needed a list of all available commands on the system. Here are a few ways you can achieve that.

Since the PATH environment variable contains a list of directories with executable files, we could start by iterating over files in those directories, filtering them, and caching the result, but your shell is typically already doing all that job (in a pretty efficient way).

compgen

If you're using bash, compgen is a handy built-in command, which can provide us with the data that is used for the auto-completion feature.

We can get list of all command names by providing the -c switch:

compgen -c

And we can easily sort the result:

compgen -c | sort

zsh

On zsh that doesn't work out of the box, but you can install the completion system with compinstall. You can enable it with something like:

autoload -Uz bashcompinit
bashcompinit

This will provide you with a compgen command which works similarly to the bash version.

Alternatives

If your directories in $PATH are relatively clean (containing no extra files), the solution could be as simple as this:

IFS=:; ls $PATH | sort -u

Note: Since $PATH uses a double colon as a directory separator, we can't give it directly to ls. Instead of manipulating the string with something like sed, I'm using IFS variable to change the standard input field separator (more info: Linux/Unix: Understanding IFS (Input Field Separators)).

In practice, directories in $PATH aren't always super clean, so instead of ls, we can use find to filter only executable files:

IFS=:; find $PATH -type f -executable -maxdepth 1 -print | sort -u

Note: if you're using non-GNU version of find, you'll have to use something like -perm +111 instead of -executable.

And since we're only interested in commands, and find doesn't support returning only the last part of the path, we need to do that ourselves:

IFS=:; find $PATH -type f -executable -maxdepth 1 -print | sed 's|.*/||' | sort -u

stest

There's a nice util called stest (part of "suckless" tools) which we can use here instead of find and sed:

IFS=:; stest -flx $PATH | sort -u

Installation

stest is usually a part of the dmenu or suckless-tools package, depending on the distro:

# deb-based
apt install suckless-tools

# rpm-based
dnf install dmenu

# Arch
pacman -S dmenu

Ask me anything / Suggestions

If you have any suggestions or questions (related to this or any other topic), feel free to contact me. ℹī¸


If you find this site useful in any way, please consider supporting it.