How the Name of the Terminal Command Works in Bash / Linux

Share
In this article, we'll learn a bit about how the name of the terminal command is resolved on Linux, or, more specifically, how the zeroth argument works in Bash.

The Zeroth Argument

Whenever we type something in the command-line in Bash, the arguments are separated by spaces, and the first argument is the zeroth argument. For example:

Let's start from the beginning with the simplest example:

date +%R

Above, we have two arguments:

  1. date
  2. +%R

The zeroth argument is usually the program that will be executed by Bash. But there are cases it's not the name of a program.

Note: programs have access to this zeroth argument, but it's advised to not use it for anything as the shell can just pass anything it wants as the zeroth argument and this has caused giant bugs in the past.

Single-Word Commands from Default Directories

Most of the time, a single-word command is the filename of an executable file found in a default system directory where system utilities are stored. These system directories include /bin and /usr/bin. The bin stands for "binaries." Binaries are another name for a program, in particular compiled binaries as opposed to source code.

An executable file on Linux is any file that has the executable permission [What Read, Write, and Execute Permissions Mean on Linux]. They aren't necessarily compiled binaries. An executable file can be a script, and Bash is able to execute it if it contains the appropriate shebang (#!) declaration.

For example, date is found in /usr/bin/date. We can find the location of a command using the which command. (below, $ represents the shell prompt)

$ which date
/usr/bin/date
$ which ls
/usr/bin/ls
$ which which
/usr/bin/which

Note: in some operating systems, like Linux Mint, /bin is a symlink for /usr/bin, which means they're both the same directory. You can check if this is the case in your system with stat /bin.

Absolute Filepaths to Executable Files

The zeroth argument may also be an absolute filepath to an executable file. For example:

/usr/bin/date +%R

This will make Bash execute /usr/bin/date.

Relative Filepaths to Executable Files

If you have a script file in your current working directory, you can execute it by typing its filename preceded by ./. The dot (.) means "current working directory" in a filepath.

For example, let's say you have a Python script called script.py. It contains this code:

#!/usr/bin/env python3

print("Hello world!")

We can execute this Python script in two different ways.

First, we could simply use the python3 command directly.

python3 script.py

If run which python3, you'll see that it's located in /usr/bin/python3.

By convention, the first positional argument passed to a program that can open files is the filepath of the file it should open. python3 supports this convention, so we can tell it to execute a script by giving the filename of the script as its first argument.

Alternatively, we could make Bash execute the script directly. To do this, we would type this on the command-line instead:

./script.py

In order for this to work, two things are necessary.

First, you must have executable permission on the script file. If you own the file, you change make it executable with the command chmod +x script.py.

Second, the file must have a shebang declaration. Since there are all sorts of scripting languages, there is no way for Bash to know what is the correct interpreter for a script file. It must be included in the script file itself.

In this example, our shebang reads #!/usr/bin/env python3. If we run /usr/bin/env python3 in the command-line, it has the same effect as executing python3 (type exit() to exit Python's interactive interpreter, by the way). We need to use /usr/bin/env because we can't just use python3 in the shebang, it must be an absolute filepath, and the location of python3 (or similar interpreters) may vary from operating system to operating system (it's not always in /usr/bin/python3). The /usr/bin/env utility provides a way to solve this issue so Bash or another shell always finds the right interpreter if you try to use that same script file in another system.

In effect, ./script.py will mean the same thing as /usr/bin/env python3 ./script.py, which in turn is the same thing as /usr/bin/python3 ./script.py.

Built-in Commands

Bash has a number of built-in commands that are not programs. These include, for example, cd. If you try to use which with them, the output will be nothing.

$ which cd
$

This is a minor technical detail. It just means that the shell itself handles the command, so it doesn't invoke any programs, nor is any process spawned.

Aliases

In Bash, it's possible to say one word is another word for a command using the alias statement. You can use it whenever you want.

$ alias foo="echo hello world"
$ foo
hello world

Above, we have aliased foo to echo hello world, which means typing just foo in the command-line has the same effect as typing echo hello world.

When Bash is initialized, it runs a configuration script located in your home directory called .bashrc. This is a dotfile, so on some file managers it's treated as a hidden file. If .bashrc contains any alias statements, those aliases become aliased every time you open the terminal.

Note: distributions often have a default .bashrc created for the user which can be rather long. It's not recommended to edit the .bashrc file directly if you can avoid it, since it's hard to track what changes you made. Many configuration files on Linux will dynamically load additional configuration from other files by default to avoid having the user edit the main file directly. For example, on Linux Mint, .bashrc automatically executes all scripts it finds in ~/.bash_aliases, if such directory exists. This means that the recommended way to add aliases isn't to edit .bashrc directly, but to create the ~/.bash_aliases directory yourself and then add some files in there to be executed by the shell.

The alias doesn't need to be a full command. We could, for example, use alias foo=echo to make foo hello the same thing as echo hello.

Variable Substition

As the zeroth argument isn't special in Bash, it can be subject to all manners of variable substitution, just like any other argument. For example:

$ FOO=echo BAR="hello world"
$ $FOO $BAR
hello world

Above, we've set the variable FOO to "echo", and BAR to "hello world". Consequently, $FOO $BAR means the same thing as "echo hello world".

Spaces and Escaping

The zeroth argument is also affected by spaces and escaping like other arguments in the command-line. See [How to Pass Arguments to Terminal Commands in Bash / Linux] for details.

Written by Noel Santos.

About the Author

I'm a self-taught Brazilian programmer graduated in IT from a FATEC. In a world of increasingly complex and essential computers, I decided to use my technical expertise in hardware, desktop applications, and web technologies to create an informative resource to make PC's easier to understand.

View Comments