What happens when you type ls -l in the console? — Revised and improved!
What happens when you type ls -l in the terminal?
Do you know? I thought I did, but I was far from fully understanding the process. It’s simple to understand once you learn what happens behind the scenes, but much of what happens we don’t see in the terminal. This was a question we were asked this week in class at Holberton School, and it opened by eyes to what happens to commands in the terminal.
The first operation that is performed is the reading of the input from the user. When the enter key is pressed, the shell uses a getline routine and the read() system call to save the input in a buffer and send it down the line for multiple processing steps.
The first step is saving the input for writing into the history file. The history file is an unedited list of the last commands entered into the shell, so the command needs to be saved before it is processed.
The next operation that is performed is alias expansion. The first word typed into to command is checked against the shells list of aliases. If there is a match, it will expand the matching value, replacing the alias in the command.
After alias expansion, comes variable expansion. Any commands following a $ will be changed to their programmed counterpart. General standards state that $? will expand into the last return value and $$ will expand into the process id. Any other $KEY will be expanded to the matching VALUE in the environment. If there is no matches, the $ is simply removed from the command string.
Now the command is at a state that it can be literally processed. The string will be sent to a tokenizer, that will create tokens out of each whitespace delimited word in the command. This can happen many ways under the hood, but it will result in pointers to each of the unique tokens.
Now it's time to run the built-in routine. The first token will be compared verse any possible built-in commands that the shell has. If there is a match, that command will run with a full copy of the command arguments.
In our ls -l example, no built-in would be found, and the shell will move on to the last pass of the interpretation process: the execution routine. The token ls will be searched for in the $PATH until it either finds a match, or does not. No match will result in a printout of "command not found" and a return of the prompt.
But we should be in luck! as ls is a command found on all linux distributions. The shell now needs to fork(), creating a new thread for which to run the ls program on. The shell will be made to wait() while the ls program is ran with the execve() system call. The execve syscall will execute the program with the arguments created in the tokenizing process, thus the ls program takes the argument -l as a command line argument. Ls will be made to its designed function, in this case listing those files in the directory using the -l mode.
On completion, the program exits, terminating that thread and returning status to the parent.
Now one full pass of command and interperate has completed, and the system returns the prompt-stored in $PS1 and waits for the next command.
There are a lot of steps that go into every command a computer receives. Most users barely see anything that happens when they execute a program or type in a command, but by better understanding how a computer handles our input, we gain a sharper ability to use the power given to us. Today we saw that even a simple sequence of 5 characters, ls -l, generates a bunch of operations in the computer before giving us back the result.
Never miss a story from Justin Marsh, when you sign up for Medium. Learn more