What (“WTF”) happens when you type ls -l in the shell.

Hugo Alberto Trujillo Martinez
6 min readAug 22, 2019

The shell is a program that takes keyboard commands and passes them to the operating system to carry out. Almost all Linux distributions supply a shell program from the GNU Project called bash. The name “bash” is an acronym for “Bourne Again SHell”, a reference to the fact bash is an enhanced replacement for sh, the original Unix shell program written by Steve Bourne. The shell runs in a terminal. A terminal is a text-based interface that allows you to type and execute commands to your operating system.

What happen when we type ls

The “ls” command is a command-line utility for listing the contents of a directory or directories via standard input. It writes results to standard output. To show the contents of a directory pass the directory name to the ls command. This will list the contents of the directory in alphabetical order.

The syntax for the ls command is as follows:

ls [OPTIONS] [FILES

When used with no arguments, the ls command will list the names of all files in the current working directory.

Long Listing Format

The default output of the ls command shows only the names of the files, which is not very informative. When the long listing format is used the ls command will display the following file information:

  • The file type
  • The file permissions
  • Number of hard links to the file
  • File owner
  • File group
  • File size
  • Date and Time
  • File name

The -l ( lowercase L) option causes ls to print files in long listing format.

ls -l

output:

  • rw-r — r — 1 root root 337 Oct 4 11:31

The first character shows the file type. In our example, the first character is - which means regular file. Values for other file types are as follows:

  • - - Regular file
  • b - Block special file
  • c - Character special file
  • d - Directory
  • l - Symbolic link
  • n - Network file
  • p - FIFO
  • s - Socket

Next nine characters are showing the file permissions. The first three characters are for the user, the next three are for the group, and the last three are for others. You can change the file permissions with the chmod command. The permission character can take the following value:

  • r - Permission to read file
  • w - Permission to write to file
  • x - Permission to execute file
  • s - setgid bit
  • t - sticky bit

In our example, rw-r--r-- means that the user can read and write the file and the group and others can only read the file. The number 1 after the permission characters is the number of hard links to this file.

The next two fields root root are showing the file owner and the group, followed by the size of the file (337), shown in bytes. Use the -h option if you want to print sizes in a human-readable format. You can change the file owner with the chmod command.

Oct 4 11:31 is the last file modification date and time. The last column is the name of the file.

ls -l → executable /bin/ls → tokenize {“/bin/ls”, “-l”, “NULL”}

The shell is prompted and then, enters some command(s) which are read to standard input using the system call getline() that reads an entire line from standard input up to the \n character to a buffer.

Next, the line read to the buffer is tokenized which is just a complex way of saying that the words in the string are broken up into “real words” using the strtok() function. This is done by counting how many words (separated by given delimiters) are in the input string, how long each substring is (the word separated by a space), and traversing the input stream and copying words (separated by the delimiter) into newly allocated memory.

The shell will check if the first token is an alias. What this means is it checks if the command (read: user inputted string) is an identifying string for a command or set of commands that the operating system can launch.

Here is an example of creating an alias where the ls -l command we’ve been using throughout the post is being attached to the alias command lllwhich has no meaning prior to us creating an alias for it.

When we type anything at all at the command line, ls or otherwise, the Shell undergoes a three-step search process. First, the Shell tries to match the keyboard input with any aliases defined in the system. Upon successful matching, corresponding text is replaced before the Shell proceeds to search for the entire command. For example, if our system included an alias that defined ls as cd, the Shell would replace our input with the text cdbefore proceeding (to learn more about using this cool Shell feature, read this). Otherwise, and as is the case with our ls input here, the Shell begins to search for the entered command as given.

Second, after attempting to match aliases, the Shell checks if the first word of the entered command represents a built-in command. Built-in commands are contained directly within the Shell, and thus can be executed automatically, without the need to run a separate program. Different Shells feature different built-in commands — one such commonly-used one in bash is echo. You can view more at this link.

Finally, after replacing any corresponding aliases and in the case of failing to identify a built-in command, the Shell proceeds to match the input with a process identifier. Linux works on two classes of content — files and processes. The ls command represents the ladder, an executable program identified by a unique process identifier (aka. PID). When the Shell searches for a given command, it searches for its corresponding PID in another environment variable, PATH, which contains a colon-separated list of directories.

At this step the shell will know that the token is not an alias and the next operation to run is to check if the command is a “built in” command.

At this point the string (user entered command) is not an alias and is not a built-in so therefore it must be a custom command. When Linux identifies that it is a custom command the following steps are taken:

  • the PATH is passed to the tokenizer strtok() by using the : delimiter to break up the path into tokens.

Input:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Output (tokenized):

/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games

Output (command appended):

/usr/local/sbin/ls
/usr/local/bin/ls
/usr/sbin/ls
/usr/bin/ls
/sbin/ls
/bin/ls
/usr/games/ls
/usr/local/games/ls

If the executable is found the process is forked by fork(), creating a child process (the executable being the parent process so we duplicate them).

Finally, the shell runs the end of the program procedures that the engineer developed into it: (i) free stack and heap memory (ii) recalls the main function (iii) re-prompts the symbol in the start_shell() file.

reference: What happens when you type ‘ls *.c’ and hit enter in your shell? by hakogh14; How to List Files in Linux using the ls Command by Linuxe

--

--