What happens when you type ls -l in the shell
When a user types ls
in a command line, the files of the current directory are displayed. ls
is short for ‘list’. The -l
is an option of the ls
command, one of several, which stands for means ‘long’, or ‘long format.
When a user enter ls
int a terminal, they will get back a list of files like this
When ls
is accompanied by the -l
command, the result looks like this
That’s what the output is when you type in this ls -l command, but what is really going on behind the scenes, on the lowest level of your systems? To answer that we need to understand what is happening in the shell.
What is a Shell?
The shell is a program that takes commands from the keyboard and passes them to the operating system to interpret and execute. The shell is a text-only interface that is run via the system’s terminal.
Today the shell has mostly been surpassed by the Graphical User Interfaces (GUI) such as Windows and Os/x. Despite this, the shell is still a powerful environment for users who take advantage of its difficult learning curve, and is often a more efficient and flexible way to use your computer.
How does it work?
When you enter a shell, you will be greeted by a command prompt, which can vary from shell to shell, but is often a ‘$’ or a ‘>’’. The prompt is running in a loop; in our case we chose to use a do while loop to display our prompt.
A function that reads user input is called when the user types in a command called by the getline
() function. The user input then gets passed to a command which filters the two types of arguments in a shell: executable system calls like ls
and pwd
and builtin functions.
Builtin functions are those that are called from the source code of the shell as opposed to external executable commands, which are called are called from the file system and originate in the system’s kernel.
Where is ls
called from?
Before the command is filtered between builtin and executable, and ls -l
is found to be an executable, and after the user input is read, it is parsed by a function we wrote. Then we call a function to tokenize the user’s argument into an array using strtok()
. The string tokenizer accepts two parameters, a string and a deliminator, and returns the string that it’s passed as a pointer to a NULL terminated string. This step is crucial for the shell to work, as will be explained in the next part.
Where is the ls executable?
The PATH
is a string of directories which contain the executable functions.ls
and all the other commands are found within the directories of $PATH.
When looking for the directory that contains the executable for ls, we concatenate a /
to each PATH
directory, appending ls
to each directory in order to find bin/ls, which contains the functionality of the ls
command.
When the correct bin directory is found, our function will call the fork
system call, which is essentially the start of our shells execution. fork
allows the program to create child and parent processes, each with a unique process identification number, or pid.
By following the pid
process, we have an integer to follow and compare in our conditional statements, allowing us to call execve
at the appropriate time.
When the correct process is running ,the execve
system function is called to actually execute the bin/ls
executable, thus listing the directory files in long for order.