Behind the Scenes: Typing ls -l in the shell
27.08.2019 — By Yashey Mateen & Jessica Bathel
View Original: Jessica ; Yashey
What is the shell?
Put simply, the shell is a program that allows the user to input and execute system commands. It uses a command prompt: (i.e.)
trusty64@ubuntu:~/shell$
to ask for user input/commands and interprets them once they hit ENTER.
But wait, what about the kernel?
“The main difference between kernel and shell is that the kernel is the core of the operating system that controls all the tasks of the system while the shell is the interface that allows the users to communicate with the kernel” — Difference Between Kernel and Shell
Once you understand the differences between the operating system, terminal, shell, and kernel then you can understand what happens under the hood when you type a command such as “ls -l”.
→ For Further Reading: https://www.integralist.co.uk/posts/terminal-shell/
What happens when you enter a command in the prompt?
When a command is entered into the command prompt the operating system will execute a series of processes in order to identify the particular command and perform it properly:
- Retrieve User Input
- Parse and handle special characters
- Executing Commands
- Returning to Prompt
We could write a bible on the hundreds of commands available to the user, with their complexities, arguments, options, environmental variables, but you would probably stop reading right here.
**Let’s just stick to what happens when you enter the command “ls -l” in the command line.
So What Exactly Happens With ls -l
Before we get into that, let’s go over variable expansion. It basically means that the terminal or bash is able to access and manipulate values of variables and their parameters. However, in order to do that, it needs to find where the executable programs are: They are located in the environmental variable (denoted with a ‘$’ before it) called $PATH. This is where all the built-in commands, like “cd” are located. The following is what the output shows when typing in $PATH:
Once your command line commences expansion, the bash will process it in a way that it can be interpreted one piece (argument) at a time. So it splits your command into “ls” and “-1”, with ls as the primary command it needs to find using the built-in getline() system call. It does this by a string tokenization function, strtok(), that basically splits the command line into tokens, using a space character as a delimiter (You can also specify additional delimiters).
Once it finds the command, it then interprets the flags given to that command, in this case -l. Cue, another built-in command, execve() process that runs the ls -l command to list more things to STDOUT (standard output). Before we can get to the output however, it’s important to understand the underlying processes when commands are being executed.
Parent Process is Forked — Creating A Child Process
The key factor is that the commands are being executed after a system call to fork(). This system call clones the parent process and executes its own processes based on whether certain conditions are met. While the child and parent processes run simultaneously, they have different PIDs (process IDs), thus they run different code. In the case of ls, fork() will create a child process and return the output to STDOUT if the executable is found inside $PATH, for example /bin/ls/. While this occurs, the parent process waits for execution to to be completed and the child process is terminated, after which memory is cleared, and the parent process takes over again and waits for the next input from the user. Conceptually:
[1] fork()
[2] wait()
[3] execve()
When wait() returns, an exit status is defined as well, which signals the process to terminate via a pointer if status is NULL. If no child process is created, then wait() returns “-1” immediately, given that the process has no child processes for which to wait.
Alas, the Final Output
After the shell finishes executing the series of processes when commands are entered, the output you get in the case of “ls -l” contains a list of your files and directories with the following information:
- File Permissions
- Number of Hard Links
- Owner Name
- Group Name
- Size in Bytes
- Time Stamp
- Name of the File
- File Type (Depending on whether it is a directory or just a file)
And thus the cycle continues, as the terminal runs another iteration of the main shell loop, while it continuously keeps track of the number of iterations, errors, & executables from each shell loop.