Before explaining the topic mentioned in the title, I will briefly explain what a shell is. In general terms, a shell corresponds in the computer world to a command interpreter where the user has an available interface (CLI, Command-Line Interface), through which he has the possibility of accessing services of the operating system as well as executing or invoking programs. The term of shell comes from the use of consoles under the UNIX operating system in the 70’s, where they were connected to the central computer and started to work there. With the rise of GNU / Linux distributions, users have several shells available and among the most pupils are: sh, bash, etc.
With the above we are already in context to continue, as users must initially run our terminal, which will show us something similar to this:
In the screenshot above, what is going on is that the shell is ready and waiting to receive a command after the $. This process is known as a wait for a command in the standard input, entered from the computer keyboard.
Once the command is typed, which for this particular case I will explain with “ls -l”, this must be followed with an ENTER, where the shell takes the line and saves it in a array of characters, together with the null character at the end “\ 0”, which indicates the end of the entered text.
This is a way in which the shell saves the above in memory:
When the shell has saved the array, the next step it performs is to separate into strings of characters, using the “space” as the delimiter, through the tokenization process, thus remaining in the memory:
Once the previous step has been completed, the shell continues with its work to verify if the received command matches a function call corresponding to the first word (ls “\ 0”, calling command), along with its predecessor, which would be the arguments (-l “\ 0”, argument to calling command) for the call command.
Then the shell will continue locating the corresponding function call, where it will try to match the first string of the command with some file located in the PATH environment variable, which corresponds to a list of directory locations separated by “:”, which are hosted in the system, and where the shell will search until you find the command (ls).
One way to show this variable is with the “echo $ PATH” command:
After the shell has searched the paths of the mentioned directories, it finally locates the executable “ls” in the / bin directory:
When the shell has managed to match the program to be executed, inside the memory it replaces the first string with the path to the directory that hosts “ls”, being as follows:
Taking into account what has been said previously, it is assumed that the command works without any difficulty, but how is the internal functioning in the system really?
To answer this question it is necessary to understand that in Linux there are two elements that are the files and the processes. For our case the entered command “ls” is a file, that when it is executed, the system creates a process corresponding to an instance of a running program and that has an ID or PID, which is not more than a unique number, used by several functions or system calls (syscalls) to manipulate these processes.
When I refer to the system call, this means that it is a mechanism by which an application requests a service to the operating system and of which we will comment later.
Once the shell executes the command previously entered by the user, this is done by making a system call (syscall) to create a new process, but we must bear in mind that if the shell is already a process itself, the new process will be created within the shell process. This is called the parents and children process. Child processes are secondary because they are created from the main shell process.
To better understand this theory, let’s start by analyzing what happens since the shell starts, at this point a parent process is created that will remain active until the shell is closed with any PID:
Once you have entered the command “ls -l” and the shell has already validated the PATH and is ready to run from / bin / ls, it creates a new process using a syscall fork ( ), this is where the child process appears.
After the child process is created, it is where you can execute the entire entered command / bin / ls -l. To achieve this task you must make another syscall execve(), which is responsible for receiving as parameters the command / bin / ls and its flag -l, which will be executed in the child process, confirming the success of the execution with another syscall exit(), with a value of zero.
When executing the execve () is finished, the child process will be terminated with another syscall wait (), which is responsible for the successful completion of the child process before returning to the parent process:
Finally with all the above the command “ls -l” is executed in question of milliseconds, without the user being aware of what happens inside the system, with the following result:
Following the previous result, the shell will again be waiting for a new command to be entered to execute: