Journey through my simple_shell using ls -l as your vehicle!

Andres Lopez
6 min readNov 26, 2020

--

It is quite remarkable what happens behind the scenes when you enter a simple command in a shell. Let’s start by defining what is a shell: it is a command interpreter running in a text based interface waiting to receive user’s input through the STDIN (standard input). My simple shell is my rendition of a custom implementation of a shell from the ground up mimicking and trying to include some of the same features a complete shell supports.

Initialization

The first step in the entire journey is the initialization of the program and it starts with the inception of functions that will work together to interpret the commands c. I am currently standing inside my directory containing all .c files that will then be compiled with GCC (GNU Compiler Collection). I wrote a story explaining the process in detailed fashion. https://medium.com/@profesor.de.ingles/the-journey-of-a-c-program-through-the-gcc-compiler-fd5b11b5644c

Once our files are compiled (with the appropriated flags) we obtain an executable (with the flag -o you generate a custom name) called hsh, in order to execute it we need to input the appropriated command for it “./hsh” once this happens we are inside our custom shell.

prompt running and waiting for user input.

This prompt is generated with an infinite loop that operates differently depending on the different command options it received, inside the loop different things happen, a shell should work in two different ways, an interactive and a non interactive mode. Bellow you’ll find a flow chart explaining the different tasks performed whenever hsh is executed.

Interactive mode

It means our loop is live and waiting for user interaction (no pun intended, or is it?) it is now when we procced to input the command we will analyze to understand the following steps -ls l. This command is received through the prompt (by pressing the enter key) and stored in a buffer, before it is even interpreted different things could happen, some of the features it can achieve is interpreting input signals such as ctrl + c or ctrl + d, the first one is going to take me back to our loop, the latter is going to exit the shell back to the current directory.

our ls -l looking nice in our prompt

Once the command is stored in the buffer our shell first asks if it was save correctly or if a NULL was stored (a enter keypress perhaps?) if that happens it will immediately prints the prompt again waiting for input again (I know right?).

prompt waiting after (enter key is pressed) interpreted as a NULL character.

Ok let us continue with the process, it then asks if the command is a built-in function such as: exit (which exits back to the directory, after freeing memory of course) or env (which prints the current environment and takes you back to the prompt). see example bellow:

Since our command is not a built-in the journey continues, it takes our command to our execution functions where it first checks if the input command is already an executable found in the PATH. (BTW it won’t execute a program in the current directory unless you put ./ before).

Since our command is not an executable yet which in this case should be /bin/ls + -l as our flag it is not ready to be executed, not before it is tokenized.

What is tokenized you asked? glad you did, in this process the command is first divided into actual words separated by a space, in this case we end up with an array of words which includes ls in one an our flag -l in the other, if that happens it then compares them with the executables find in our PATH, once it finds a match it pairs it with it and is then when you can actually execute the command. When a pairing is not achieved it returns the command stored in the buffer with the appropriate error message after freeing memory from all the pairings that occur before.

it also prints the number of times the loop was execute in this case just 1.

At this point our command went from ls -l to become /bin/ls -l which is now an executable. At this point we confirm it is now a readable command but what is that command for? Awesome you asked again!

ls is a shell command which is used to print all the files and directories in our current directory in the form of a list (pun intended).

command printed to STDOUT after ls is interpreted as /bin/ls

Whenever you include the -l (flag) it stands for long format and it is able to print more information which includes the total amount of files in the directory, the permissions every file has which you can even change using the chmod command (a story for another day perhaps?), if it is a directory the amount of files it contains, next you’ll find the name of the owner and group that owns the file or directory. Then you will find the size of the file in bytes followed by the date of the last modification ending with the actual file name. Once that information is sent to STDOUT we are taken back to our prompt waiting to receive a new command, awesome right?

result in STDOUT of our complete command /bin/ls -l in this case

Non Interactive mode

In this mode some of the tasks mentioned before are performed, the way it works is by sending the desired command through the bash built-in echo with pipes “|” in order to execute it. as before it is able to interpret it, tokenize it and send the appropriate result being a successfully found command or an error message before exiting the shell and displaying the bash prompt again.

here our command was executed on the background before exiting and showing the bash prompt again.

It is not as fun as the interactive mode but it does work. By this point you were able to follow the journey of a single command behind the scenes, thanks for going through this process with me. I got to appreciate this process even more once I was able to give birth to my own version of a simple shell as per the name with my project partner.

It has been a journey for me as well! getting to this result was a complete learning experience, three months ago I didn’t have any idea of all the magic that goes behind a program, how everything is connected and how we are able to transform simple words and numbers into something greater. I am still a complete beginner inside this vast and amazing world of programming. If you were able to get to this point that means you are either interested or bored maybe even both? You dealt with some bad jokes but I hope that at the end of the day you could grasp a bit of knowledge behind this amazing quite mind-blowing world. Thanks for reading!

--

--

Andres Lopez

Programmer in the making, English teacher and Industrial Designer, Avid Gamer and amateur mountain biker.