69

What can I type at my shell (which happens to be bash) that will list all the commands that are recognized?

Also, does this differ by shell? Or do all shells just have a "directory" of commands they recognize?

Secondly, different question, but how can I override any of those? In other words how can I write my own view command to replace the one existing on my Ubuntu system, which appears to just load vim.

1

7 Answers 7

100

You can use compgen

compgen -c # will list all the commands you could run.

FYI:

compgen -a # will list all the aliases you could run.
compgen -b # will list all the built-ins you could run.
compgen -k # will list all the keywords you could run.
compgen -A function # will list all the functions you could run.
compgen -A function -abck # will list all the above in one go.
2
  • 11
    Note that compgen -c will include things like { or while that are not strictly speaking commands. Commented Jul 28, 2015 at 11:41
  • 1
    You might want to add that compgen only works for bash. It does not work for any other shell I know; be they sh-compatible (e.g. ash, dash, busybox sh, ksh, mksh) or not (e.g. csh, tcsh, zsh, fish, ...).
    – Socowi
    Commented Nov 12, 2023 at 16:55
24

A shell knows four kinds of commands.

  • Aliases: these are nicknames for a command with some options. They are defined in the shell's initialization file (~/.bashrc for bash).
  • Functions: they are snippets of shell code given a name. Like aliases, they are defined in the shell's initialization file.
  • Builtins: the shell comes with a small number of built-in commands. Most builtins manipulate the shell state (cd changes the current directory, set changes options and positional parameters, export changes the environment, …). Most shell offer largely the same builtins but each shell has a few extensions to the basic set.
  • External commands: they are independent of the shell. Like other programs, the shell executes external programs by looking them up in the executable search path. The PATH environment variable contains a colon-separated list of directories to search for programs.

In case there are commands of several types by the same name, the first match in the order above is executed¹.

You can see what type of command a name corresponds to by running type some_name.

You can list aliases by running the alias built-in with no argument. There is no way to list functions or builtins that works in all shells. You can find a list of builtins in the shell's documentation.

In bash, the set builtin lists functions with their definitions as well as variables. In bash, ksh or zsh, typeset -f lists functions with their definitions. In bash, you can list all command names of any type with compgen -c. You can use compgen -A alias, compgen -A builtin compgen -A function to list commands of a specific type. You can pass an additional string to compgen to list only commands that start with that prefix.

In zsh, you can list the currently available commands of a given type with echo ${(k)aliases}, echo ${(k)functions}, echo ${(k)builtins} and echo ${(k)commands} (that last one lists external commands only).

The following shell-agnostic snippet lists all available external programs:

case "$PATH" in
  (*[!:]:) PATH="$PATH:" ;;
esac

set -f; IFS=:
for dir in $PATH; do
  set +f
  [ -z "$dir" ] && dir="."
  for file in "$dir"/*; do
    if [ -x "$file" ] && ! [ -d "$file" ]; then
      printf '%s = %s\n' "${file##*/}" "$file"
    fi
  done
done

There is an edge case in Bash: hashed commands.

Bash Reference Manual says:

A full search of the directories in $PATH is performed only if the command is not found in the hash table

Try:

set -h
mkdir ~/dir-for-wat-command
echo 'echo WAT!' >~/dir-for-wat-command/wat
chmod +x ~/dir-for-wat-command/wat
hash -p ~/dir-for-wat-command/wat wat
wat

The PATH environment variable doesn't contain ~/dir-for-wat-command, compgen -c doesn't show wat, but you can run wat.

If you want to shadow an existing command, define an alias or a function.

¹ Exception: a few builtins (called special builtins) cannot be shadowed by a function — bash and zsh don't comply with POSIX on that point in their default mode though.

1
  • 1
    Another edge case is for values of $PATH like /bin:/usr/bin: (trailing :), where it would fail to list the executable files in the current directory. Commented Jul 28, 2015 at 11:45
7

Try this, using :

(   # usage of a sub processus: the modificaion of PATH variable is local in ( )
    PATH+=:EOF # little hack to list last PATH dir
    printf '%s\n' ${PATH//:/\/* }
)
0
3

The list of commands consists of two sets:

  1. The commands built-in to the shell
  2. The commands in your PATH

You can't change built-ins, but you can keep the shell from using a built-in by specifying the full pathname like /bin/echo.

As for the commands in your PATH, you can change that. PATH is a colon-separated list of directories to look for commands in. The first matching file found "wins".

export PATH=~/bin:${PATH}

(This syntax does not work for csh-derived shells, but all others that I know about).

That exports PATH with ~/bin as the first entry followed by the rest of the existing PATH entries. So now your shell will check directory calledbinin your home directory for a command *first* before checking the standardPATH` the system set up. You could easily make it check the new directory last by instead using:

export PATH=${PATH}:~/bin

To make the PATH persist for future logins, add it to a .profile or other shell rc file.

1

If you press tab key twice and then y, you will get the list of all available command in your current shell. For the second question I think you should use alias: shell alias.

13
  • regarding alias, is that a fool-proof way of overriding and un-overriding (by "unaliasing") a command when it is called anywhere on the system (for example from a shell script)?
    – themirror
    Commented Oct 12, 2013 at 17:39
  • 1
    What shell do you use? I can't get the double tab to list all commands on my bash.
    – terdon
    Commented Oct 12, 2013 at 17:46
  • I use bash on Ubuntu 13.04. There is also a command called compgen which can be used to get the list of all available commands on the bash.
    – Vombat
    Commented Oct 12, 2013 at 17:51
  • @terdon Do you have bash completion installed?
    – Vombat
    Commented Oct 12, 2013 at 17:53
  • 1
    set show-all-if-ambiguous off
    – Vombat
    Commented Oct 12, 2013 at 18:19
1

In the bash shell, for the list of aliases, reserved words, functions and external commands in directories of $PATH (assuming none of them contain newline characters) sorted alphabetically:

compgen -ac | sort
0

@Gilles_Quenot's solution without paths, the pure commands:

printf '%s\n' ${PATH//:/\/* } | xargs -n 1 basename

(@Gilles_Quenot sorry, no reputation to comment)
There are more than 3600 commands ( printf '%s\n' ${PATH//://* } | wc ), so a file could be better:

printf '%s\n' ${PATH//:/\/* } | xargs -n 1 basename > commands.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .