When you type ls -l, where the shell go?

Arquimedes
6 min readAug 20, 2020

By Jocelyn Vega & Ricardo Arquímedes Castro

execution of ls -l command

Before you know what happens when you type ls -l, do you know what is a Shell?

A shell is a command-line interpreter, it is the computer program that provides a user interface to access the services of the operating system. Depending on the type of interface they use, shells can be of various types, in this case, a shell program of the type sh (Bourne Shell) will be developed.

One of the most ussed shell program is bash, which is utilized on Linux systems. You find the bash in the /bin directory.

How work the shell command?

Users typically interact with a shell using a terminal emulator that is used for entering data into and displaying or printing data from, a computer or a computing system.

In the line command, the users enter an input after this be displayed the prompt string stored in the enviroment variable.

The command prompt and terminal appearance are governed by an environment variable called PS1. According to the Bash man page, PS1 represents the primary prompt string which is displayed when the shell is ready to read a command.

After prompting, the shell wait until it receives the commando on standard input, of any text entered from the keyboard. This text not received until the user push the Enter key. At this point the shell read the line of the input and store in the string, an array character terminated by a null byte (/0).

When we execute the bash and type the command ls -l, the shell initialize the stores in the input:

After store the command received from standard input to a character array, the shell tokenizes it into an array of separate strings. This token is completed taking the spacer character as a delimiter.

After this token action, the shell contain a series of three strings as follows:

Our sheell, put in quite the work, but its not finished yet, handling our input. After the token action, its received command, the shell will attempt to match any aliases, user-defined nicknames for commands.

For most shells, aliases are defined in a given file located on the operating system in the format NAME=’VALUE’.

You can use the builtin command alias to view all aliases defined on your given system (more on builtins later):

Type alias in your shell

The shell checks this file for an alias name matching any of its tokenized input strings. In the case that a match is found, the string containing the alias is replaced with its corresponding value. For our example, we will assume that the user has not defined aliases for either of the input strings ls or -l, and the tokenized command remains unchanged.

With its input read, tokenized, split, and filtered with alias values, the shell is finally satisfied with the command. Next, it must match its received command with a corresponding function call. Specifically, for simple commands (ie. commands where the first string is not a reserved word), the shell must locate the function call corresponding to the first word. All proceeding strings are considered arguments to that calling command. In our example, this division of command and arguments goes as follows:

If this first word begins with a \, the shell interprets it as a full pathname and attempts to execute the command strings directly. Otherwise, and as is the case with our example ls -l.

The command ls without any location specified prints all the contents of the current working directory to standard output, with the option -l doing so in long listing format (ie. with additional information permissions, byte size, last-edit date, and more). Thus, in result, after entering ls -l into the shell, we get the following:

The shell checks this file for an alias name matching any of its tokenized input strings. In the case that a match is found, the string containing the alias is replaced with its corresponding value.

The shell attempts to locate the corresponding function call using a maximum of two steps:

  1. Builtin Matching

They can be invoked by entering particular commands. One such example for bash is the builtin help, which can in fact be called by itself to list brief information about all available bash builtins:

Type help in your shell

Each builtin function is invoked by the entering of a particular command string. In attempting to match a builtin function, the shell attempts to match the first input string with any of its builtin strings. If a match is made, the corresponding builtin is called. In our case, however, ls does not represent a builtin; thus bash continues to the second search step.

2. Normal Program Matching

Having failed to match a builtin, the shell next attempts to match the first command string with a file located on the given system. The shell searches for a given command’s corresponding file within another environmental variable, PATH. The PATH variable is a colon-separated list of directories through which the shell searches one-by-one until it locates the command in question. We can use one of the aforementioned builtin commands, echo, to print the value of our PATH variable:

Type echo $PATH in your shell

Our shell searches first in the /usr/local/sbin directory, then in the /usr/local/bin directory and so on until it locates the directory containing access to the executable file ls

Type \ ls /bin on your shell

Before execution, ls is nothing but the former, a file, but when run, a process is created, an instance of the execution of that computer program. This process is identified by a process identifier (aka. PID), which is simply a unique number.

Systems Calls

Processes are created within system calls (syscalls), methods through which programs interact with the kernel of the given operating system. As users, we can make syscalls through pre-provided programs — a complete UNIX/Linux list of which you can view here.

When the shell goes about executing a received command, it does so by making a syscall to create a new process. If processes are only single instances of a computer program, however, and the shell program itself represents one such active process.

To execute a command, the shell takes advantage of the system of parent and child processes. Child processes are processes created within processes. Every single process is actually a child — as in, every process is created by some parent tracing back to the initialization of the kernel itself. Note, however, that while every process is a child, not all processes contain children themselves.

Sources and references:

--

--

Arquimedes

Beginner Programar, social comunicator. Love pop music, family and friends.