What really happens when you type ls *.c

Jack Gindi
3 min readSep 11, 2018

--

“I know Kung Fu” -Neo

“ls” is one of the most useful commands in bash. Listing files can give you a lot of information in a very concise format. Typing “ls *.c” into your terminal will give you a list of all the C programs in your current working directory. But what’s really happening under the hood?

First, let’s look at the basic relationship between the shell (which, for this example, is bash), the program which interprets the commands you type into it, and the kernel, which is the cornerstone of any operating system. The kernel manages resources and tells your computer how to process incoming information, while the shell allows the user to input commands in what’s known as a “console emulator.”

Next, we move on to getline(). All this function does is read the standard input (or STDIN), which is where you type in the shell. Easy.

From here, the shell checks whether or not “ls” has been assigned as an alias. Then comes two options. If “ls” is an alias, it replaces “ls” with the value that was assigned to it. If it isn’t an alias, the shell checks for a built-in command with that name, which would lie within the system. It checks for applications matching the name of the inputted command in $PATH, which is an environmental variable. $PATH contains a list of every directory that the shell searches when any command is entered into it.

“echo” is an easy way to see the contents of a variable

“ls,” because it is a built-in command, is located at the address “/usr/bin/ls”. “/usr/bin”, for Unix-based systems, is usually where most of the executables related to built-in commands are.

“ls” then asks the kernel (via a “system call”) to perform three functions:

  • fork — duplicates the shell process, creating a “child” process
  • execve — stops the duplicated parent process, then loads the new program (which is “ls” in this case), then begins running said new program (again, “ls”). You could think of this as all the steps needed to execute the code within the program.
  • wait — this call keeps track of the parent’s child processes while the parent continues to perform other actions.

If no executable file with the name “ls” exists, the shell instead prints a “command not found” error, and returns to the parent process.

Ok, so we know what “ls” does. What about the “*.c” part of it?

On the surface, “*” is a wildcard. The “*” wildcard outputs any and all entries — directories as well as files! — of zero or more characters, which is interpreted not by the program (“ls” here), but by bash itself. This process is known as “shell expansion,” and in the case of “*.c”, all files that end with “.c” will be outputted.

Finally, the function that prints the results is called “PS1,” which shows the username, hostname, and full path name of the specified directory. Since there is no directory that is directly referenced in this command, it uses the current working directory.

References:
https://medium.com/@JennieZChu/the-magic-of-ls-c-c89276cd97ac
https://medium.com/@vietkieutie/what-happens-when-you-type-ls-c-into-your-shell-e2faf1ad2dbd
https://ryanstutorials.net/linuxtutorial/wildcards.php
https://medium.com/meatandmachines/what-really-happens-when-you-type-ls-l-in-the-shell-a8914950fd73

--

--