What happens when you type ls -l in the shell

Rolando Quiroz
5 min readAug 28, 2019
Figure 1. A beautiful shell in a beautiful place

The right starting point to understand what really happens when you type ls -l and hit Enter in a shell, it is to understand the relationship between the kernel, the shell and the user.

Figure 2. The User, the Kernel and the Shell

The kernel is the core of the operating system. Kernel interacts with the hardware on demand from applications and provides many system calls. A software program interacts with kernel by using system calls

A shell is an interface that allows the user to interact with the kernel of an operating system. The shell is accessed by a terminal that runs it and makes the system understand commands.

In a Linux operating system a shell takes input from user in the form of commands, processes it, and then gives an output. It is the medium through which a user works on the programs, commands, and scripts.

In a few words when the user types the command “ls -l” and hits Enter in a terminal running a shell, the kernel does all the process to shows us all the information of the files: permises, user and group to which the file belongs, the size of the file, date and time of creation and name of the file.

Figure 3. The output of a shell running “ls -l”

But what does it happens in deep?

At the beginning the shell prints the prompt to the stdout, and waits for the user to enter commands. To get a command line, the shell performs a blocking read operation so that the process that executes the shell will be blocked until the user types a command line in response to the prompt. When the command has been given an terminated by the Enter key by the user to stdin, the command line string is returned to the shell.

Figure 4. “ls -l”

The parsing command process begins from first left character of the line searching for white spaces. The shell watchs for alias for the string “ls”, if is the case as ls is an alias it will be replace with its real value, if not is the case the shell need to evaluate what is the word: a command a bulit-in?. For the example “ls”, the recognized word is treated as the command, and subsequent words are treated as parameter strings: “-l”.

Next thing to do is find the file for that command, shell looks for a program file called ls, and for that we need the current PATH environment variable, an ordered list of absolute pathnames that specifies where the shell should search for command files. The shell will first look in the current directory (since the first pathname is “.” for the current directory), then in /bin, and finally in /usr/bin. If there is no file with the same name as the command in any of the specified directories, the shell responds to the user that it is unable to find the command. The ls binary executable file will be located [in one of the major sub directories of the ‘/usr’ directory] in the file ‘/usr/bin/ls’‘/usr/bin’ contains most of the executable files.

At this point the shell simply passes the string parameters to the command as the argv array of pointers to string to executing the command.

Figure 4. argv[] array

Finally the shell execute the binary object program in the specified file.

The shells have always been designed to protect the original process from crashing when it executes a program. That is, since a command can by any executable file, the process that is executing the shell must protect itself in case the executable file has a fatal error in it. The shell uses the system calls fork, execve, and wait.

The first argument is assumed to be either the name of a built-in shell
command that is interpreted immediately, or an executable object file that will be loaded and run in the context of a new child process thanks to fork system call.

fork. This system call creates a new process which is exact a copy of the calling and running process except that it has its own process id and its own pointers to shared kernel entities such as file descriptors. After fork() has been called, two processes will execute the next statement after the fork in their own address spaces — the parent and the child. If the call succeeds in the parent process, fork() returns the process id of the newly created child process, and in the child process, fork() returns a zero value.

Figure 5. Fork process detailed.

execve. This system call is used to change the program that the process is currently executing. It replaces a the current process image with a new process image

Figure 6. Exec, wait and exit system calls.

wait. This system call is used by a process to block itself until the kernel signals the process to execute again — for example, because on of its child processes has terminated. When the wait call returns as a result of a child process terminating, the status of the terminated child is returned as a parameter to the calling process.

Upon completion, the child process will terminate and control will be returned back to the parent process. You will be greeted with the prompt once ls is executed and will be able to enter the next command.

Authors:

Jonathan Cardenas email: 892@holbertonschool.com

Rolando Quiroz email: 906@holbertonschool.com

References:

https://danishprakash.github.io/2018/01/15/write-a-shell.html

--

--