How the shell interprets the command ls -l

Lisa Olson
4 min readMar 28, 2018

--

Before the days of graphical user interfaces, users would interact with computer through the use of a command line terminal. The program which interprets commands and provides them to the operating system to execute is the shell. In this article, we will discuss the steps the that the Linux shell goes through to interpret the command: `ls -l`.

`ls -l` is a basic command which executes the `ls` command that lists the contents of a directory, and uses the `-l` flag to specify that the contents should be listed in a long listing format , but we’ll soon see how complex it gets when it comes to the shell’s functionality. The first step is tokenization. The shell has to interpret the single string ‘ls -l’ which we then pass to a function that splits up the string into separate ‘tokens’. In this example, ‘ls -l’ is composed of two tokens, ‘ls’, and ‘-l.’ To do this, we use `strtok()`, a function that parses strings by a specific delimiter, i.e. a space, or a colon. In this case, we split the tokens by using the space between ls and -l as a delimiter. This function replaces those found delimiters with a special character called null terminators which separates a single string into separate strings (tokens), allowing them to be easily pushed into a matrix, or an array of strings. So, in our example, the original string, `ls -l`, now is a matrix pointing to the first string ‘ls’ and a second string ‘-l’, followed by NULL terminator signifying the end of the matrix.

And that was just the first step! That was simply to be able to access each part of the command separately. Now that we have our beautiful matrix of separated strings, the next thing the shell will do for us is check for aliases and built-ins. This means that if we, as the users, have set any aliases — names to stand for other things — or built-ins — commands such as `exit` that are “built-in” to the shell — the shell will check our matrix against those strings to see what to execute.

And now we get to the fun part: execution. To talk about executing files and running commands, we need to talk about this thing called the PATH. The path is a colon-separated list of directories inside of your computer. The path is just one string in a matrix of strings stored in a special environment variable The environment variable contains data and configuration information that could be useful to an application. One of the strings in this environment contains the PATH. The PATH is useful because it contains the directories which the shell should look in to find executables. In our example, `ls` is actually just one of the many programs that is in the `/bin/` directory. When the user inputs a command or program to execute, it will look to see if is in one of the PATH directories. Without the PATH, the user would have to type the absolute path to the program to execute, in this case `/bin/ls`, in order to execute the `ls` program. However, since the shell automatically checks the see of the program to execute is in one of the PATH directories, all the user needs to do is type `ls`, and the shell will still be able to execute

the proper program. So the next job of the shell is to search through the entire matrix of strings (the environment) until it finds the PATH.

So, the shell finds a match! It finds the word ‘PATH’ within the environment and now it needs to attach the command we passed it, ‘ls’ to every file it finds in the path until it finds a match.

There are a couple different ways to go about checking a file’s existence, and further, checking it’s accessibility and if it’s executable. No matter how the programmer goes about it, what ends up happening is ‘ls’ is attached to directories in the path until it finds the executable file it was looking for. For example, ‘/usr/bin/ls’ is an executable file so it would be the final string we pass on to the next function.

This finally gets to the part we’ve been waiting for. The function runs the command ‘ls -l’. It was separated, it was found in the path, it was attached to a string in the path, it found its’ home in the path, and there, the program `ls` is run and within `ls, -l` is one of the options allowed in order to format the listing of contents.

The shell has done it’s primary job. So now what? Well, now that the ‘ls’ program has run, and the file’s contents are printed out onto the prompt using PS1 (), the shell resets itself and is ready to run again. How the shell works on a high level is that it’s constantly stuck in an infinite while loop, persay. That’s why we can continue to run command after command after command. It will continue waiting on commands unless an EOF, or a close signal is struck.

To summarize, the basic breakdown of how the shell handles the command `ls -l` is this :

  1. Split up the command into tokens
  2. Check for aliases
  3. Check for built-ins
  4. Find the command in the PATH
  5. Call the program
  6. When the program is finished, print the prompt using PS1
  7. Wait for the new command

There are lots of tasks that the shell carries out behind the scenes in order to enable the user to carry out even commands as simple as `ls -l` to list directories. The shell is capable of interpreting many more advanced commands with more powerful functionality, but hopefully, with our description of what the shell executes with these basic commands, we hope you have developed a deeper appreciation of the shell.

--

--

Lisa Olson

Front End Developer. Passionate about everything I do. How we spend our days is how we spend our lives.