How to Talk, So Your Operating System Will Listen…How to Listen, When Your Operating System Talks

What’s happening under the hood when a user types ls -l into the shell or a command-line interpreter??

Trying to eliminate some of the blurred lines that come with typing commands into the shell.

Before we dive in, here are some need-to-knows to help you follow along. I will be operating on a UNIX/UNIX-like operating system. The shell being referenced is the Bourne Again Shell (BASH). It may also be referred to as sh or /bin/sh.

The shell is an executable program(/bin/sh), utilized by a user, to interact with and/or manipulate a computer’s operating system. The shell must be invoked, via a terminal, which is a program that opens a window to allow user or file input, for the system to execute.

If it’s determined, that standard input is connected to the terminal (via isatty), a prompt is printed. The prompt is the value stored to the environment variable PS1(prompt string 1) and is one of the only environment variable available by default in the shell. When a prompt is displayed, the shell is in interactive mode, and ready for the user to enter commands, for the shell to execute.

In the example below, ‘ ~$ ’ is the prompt before it’s changed to ‘ :) ’

You can see, I started with a prompt ~$ and through changing the PS1 value, I made it a smiley face :

That brings us to the question, what does typing ls -l, into the shell, do exactly? Ls(short for list) is a command used to list the contents of a current working directory. By default, the ls command does NOT list hidden files or those with a dot(.) at the beginning of its name. To list these types of files, a flag with an option would have to be included in the command ls (-a ← ‘-’ is a flag and a is the option to display hidden (.) files). Including an option, essentially changes the behavior of the command being executed.

This leads us to the command option ls -l, which lists the content of the current working directory, in long format. However, nothing is THAT simple when it comes to communicating with a computer, and knowing what goes on under the hood, when calling a command could save your bacon one day.

Displays the output given after executing commands ls, ls -a, and ls -l into the shell via interactive mode.

When a user types ls -l into the command line, upon pressing enter, the parent process of the shell, will fork() itself, and make a child process. Now, the processes are essentially identical at the moment, so a way to check if the process is the parent, or the child, one would simply check the return error of fork(). If fork() returns 0, it is the child process, if the process is the parent, it will return -1.

Once discovering which process is the child process, the sys_call execve() will pass in the executable file that was entered as a command, the rest of the arguments that follow, and it will take a copy of the parent’s environment variables for the child to utilize. The parent then will tell any other arguments to wait() until the other child processes get executed. However, let’s get back to shell and what happens when it’s first child process begins executing, upon hitting enter after ls -l.

The shell assumes the first word is a command name, and will first look for any special characters or if the command starts with any of the reserved keywords. In this case, ls does not contain anything of that sort, so the shell will next, look for any aliases defined, that would change the action, of the command at which is entered.

Below, is an example of a common alias a user may assign, alias rm=‘rm -i’, which asks the user for confirmation, before removing a file. By default, the command rm, upon pressing enter, would permanently remove the file passed along with the rm command, without displaying any other output. The shell will not check relative or absolute pathnames given for alias, nor will it check if the command is quoted.

An alias that verifies with the user whether they’d like to finish removing a file, upon entering rm filename

If there is not an alias discovered for ls -l, the shell will next, try to determine whether it is built-in, which are pre-loaded into memory when the shell launches, and do not need to call other programs. However, ls -l is NOT a built-in, so the shell will now check PATH, to look for an executable that matches the command that was given via the command-line interface.

PATH is a list of directories that are separated by a colon, and that is where the shell will go through, looking for the first executable file ls -l that it can find.

Upon typing $PATH, the shell will display the value of the environment variable, PATH.

The search starts from left to right, so if the left-most directory happens to be /usr/local/bin and if ls -l is NOT found, the search continues to the next directory in PATH. Once the directory containing ls -l is found, only then, will the ls -l executable be run, in which case, the output would display a list of the contents found inside the directory, in long format.

Once the directory is found, then the relative path can be used when referring to the program, and that takes into account the current working directory, however, if the exact location is unknown, the absolute path is followed from the root down to the current location.

This is a stripped-down version of what goes on underneath the hood of the shell when commands are called, but there is so much more information available to help solidify your understanding. I’d like to remind everyone, that some of the best information can be found right inside the man pages so, RTFM! As always, thanks for reading! Until next time!

Full-Stack Software Engineering Student at Holberton School