What happens when you run a Linux command? This simple act can appear straightforward, but many different things can actually occur, depending on whether you’re running an executable program, a shell script, a shell builtin, a user-defined function, or an alias.

The Different Types of Linux Commands

Aprogram(binary, or executable) is a file on disk somewhere, in a recognized format. Common formats include ELF on Linux, and Mach-O on Mac. The format is a low-level, machine-friendly one that the shell can pass off to the kernel to run.

Ashell scriptis a much higher-level form of program, written in human-readable text. A shell script can run other commands, and it can be written in an interpreted language like Perl or Python.

Example output from echoing the PATH variable in a terminal. The value is “/usr/local/bin:/usr/sbin:/usr/bin:/bin”

Abuiltincommand is internal to the shell, so it’s always available and generally runs at a low-level, to perform operations that directly affect the shell itself.

Ashell functionis like a mini shell script, packaging a set of commands together under one name. Shell functions are usually loaded so they are always available by name.

Trying to run a non-executable file in a Linux terminal gives the error message “Permission denied."

Analiasis an alternative name for any of the above. you may create a short alias of a longer command to save time and effort when running common tasks.

The order in which a shell like bash looks for these types of commands is important. To put it simply, bash tries commands in this order: alias, function, built-in, program/script.

The file command showing details of an executable binary while ls confirms that it does not have execute permission.

1Running an Executable Program

The most familiar type of command is an executable program file. Many of the most common programs are part of the POSIX standard, which means they should be available on most Unix or Unix-like systems, including Linux and macOS. Examples of such commands include cat, diff, and vi.

Other command-line programs—such as Apache, Neofetch, or tree—may need to be installed because they are typically not included in a distribution by default. But, just like POSIX command programs, they will run via a single program file somewhere on your disk.

Running an executable on the command line despite its lack of permissions.

There are two common ways to run a program. First, you can type a path to a program file, like./myprogor/usr/bin/awk. If the first part of your command contains any forward slashes, the shell will attempt to find a file at the corresponding path. For example, you can run a program at /bin/cat like this:

The shell will then check for an executable program at /bin/cat, then run it if it exists.

On Linux, executable programs usually have no file extension, so a command like “grep” is contained in a file namedgrep. This is just a convention, because it’s convenient to make executables recognizable by filename alone. However, if you really want to, you’re free to name your executables anything you want, like “myprog.exe” or “myprog.RUNME.”

The second case occurs when you type a program name without a path; for example:

With a system that’s properly set up, this should have the same effect as before, because the shell will locate the same cat program. It does so by checking a special environment variable named PATH, which looks something like this:

This is a colon-separated list of paths that the shell will search to locate a program. The order is important since you may have two files with the same name in different locations. For example, if you have a/usr/bin/grepfile and a/bin/grepfile, the above PATH will cause the shell to run the /usr/bin version. This system lets you override a system-wide command with a custom one that’s more specific to your needs, which can be very useful.

2Running a Shell Script

A shell script runs slightly differently from an executable program, and it’s a very different type of file. A simple shell script looks like this:

The first line is referred to as a “shebang” or “hash-bang” line, named after the combination of # and ! characters. This is a special instruction that tells the shell which interpreter to use for the rest of the script. In the above case, it’s the shell itself, at /bin/sh.

The remainder of the script is a text program that the interpreter understands. In this case, the shell can run commands like echo in the same way it would if you typed them on the command line.

Otherwise, a shell script is much like an executable program, and your shell will search for it using the PATH variable in the same way. For both programs and shell scripts, it’s important to note that the permissions on the corresponding file will affect how you run it. With the execute permission set, you may run the program by typing its name or path. But if the execute permission is not set, you’ll see an error:

You can always run such a file by passing its name as an argument to an appropriate interpreter. For example, you can run a shell script like this:

you’re able to even run an executable like this, but you’ll need to do some investigation first. The file command gives information about the type of a file, including its interpreter:

In this case, you can run the pwd binary using the /lib/ld-linux-aarch64.so.1 program:

3Executing a Shell Builtin

Some commands are so fundamental to the nature of the shell that they need to operate in a slightly different way. These are called builtins because they are, effectively, part of the shell themselves.

Builtins are usually low-level and commands that you use frequently: cd, echo, and kill are common examples. Unlike programs and shell scripts, these commands do not correspond to a particular file because they are part of the shell itself, compiled into the shell’s executable.

Some systems may include wrapper scripts that run builtins. For example, on my macOS system, there’s a/usr/bin/cdscript which uses thebuiltincommand to run the corresponding builtin. This is for POSIX-compatibility, and you can safely ignore the script version.

Builtins can be difficult to learn about because they either have no manual entry (e.g. on Ubuntu Linux) or they all have one big, shared manual page (macOS).Thetldrprogramis a great way of finding out more about builtins.

For similar reasons, builtins usually support far fewer command-line options than fully-fledged programs. For example, cd will usually support just two, fairly obscure options:-L(to follow symbolic links) and-P(to avoid symbolic links). This means that, sadly, options like-hor–helpare not supported.

4Calling a Shell Function

A command can also be a call to a function. At any time during a session, you can load or define a function using this syntax (in bash):

Alternatively, you can use a syntax that inserts the keyword “function” before a function name and drops the parentheses after it:

You can then call a function by typing its name, followed by any arguments. For example, I have the following helper function defined in a file:

I then load this file from my shell’s run control script (~/.zshrc), and I can run this command to create a new directory and immediately change to it:

You can call such a function on the command line whenever you like. You can also call it from scripts, but remember that it needs to be loaded (use the builtinsource, or its equivalent., to do so).

5Using an Alias

An alias is a convenience that saves you from typing long command names or common options. For example, on my system, I have an alias to ensure file listings are in color, with type suffixes:

Now, if I type just “ls,” the command “ls -GF” runs in its place.

You can create an alias at any time, using the alias builtin command, e.g.

Note that quotes are required when you run alias, if the replacement string contains any spaces. You can view all aliases by runningalias, and you can remove an alias with theunaliascommand. Again, you’ll want to add aliases to a startup file, like ~/.zshrc or ~/.bashrc, if you want them to apply across sessions.