What happens when you type ls -l in the shell
ROBERTO PALACIOS
DevOps Engineer | Cloud Computing | AWS Cloud | 2x AWS Certified | Certiprof Cibersecurity Certified |
Unix is a powerful system for those who know how to master its power. In this chapter, I will try to describe several ways to use the Unix shell, bash, more efficiently.
Sometimes, you will want to deal with more than one file at a time, actually, with many at once. For example, you want to copy all the files that start with data to a directory called /backup. This could be done by running many cp commands, or writing each file on a command line. These two methods take a long time, even, there is a good chance of making mistakes.
What really happens when we write ls -l
When we start in the shell we are first shown a prompt.
What is the prompt?
A prompt is one or several characters that are displayed in the command line and this indicates that is waiting for commands (Varies depending on the command interpreter).
user@machine:~$
once some command is executed and the command finishes its task again shows the prompt again indicating that we can perform another order or task for example
daviddlhz@LAPTOP-8746PFEQ:~$ ls -l total 24 -rw-rw-rw- 1 daviddlhz daviddlhz 17 Mar 30 10:00 ' [ ' '"Holberton School" ' '' '' ' **$ ? * * * **:)"' -rwxrwxrwx 1 daviddlhz daviddlhz 8344 Mar 30 10:30 a.out -rwxrwxrwx 1 daviddlhz daviddlhz 8528 Apr 5 00:26 axc -rw-rw-rw- 1 daviddlhz daviddlhz 296 Apr 5 00:23 axc. c drwxrwxrwx 1 daviddlhz -rw-rw-rw- 1 daviddlhz daviddlhz 271 Mar 30 10:30 main. c drwxrwxrwx 1 daviddlhz daviddlhz 4096 Apr 9 -rwxrwxrwx 1 daviddlhz daviddlhz 25 Mar 30 10:58 script drwxrwxrwx 1 daviddlhz daviddlhz 4096 Apr 16 15:14 daviddlhz@LAPTOP-8746PFEQ:~$
We can realize that to display-long-format we assign what corresponds to ls -l so that now when we use display-long-format really what our shell will do is make an ls -l, you have to keep in mind that if we run the ls -l command the same will work, but this example is given because actually our shell performs this order by first looking at the aliases.
Built-in
Built-in functions are internal functions of the command interpreter and not an external program.
for example:
We know that ls is an external function (which in turn is an executable program) of our shell and we can
verify this information with the command whereis (this command returns the path where our executable is located in addition to the path of its manual).
daviddlhz@LAPTOP-8746PFEQ:~$ whereis ls ls: /bin/ls /usr/share/man/man1/ls.1.gz daviddlhz@LAPTOP-8746PFEQ:~$
The difference is that when we try to use the same command but to find an internal function like cd this is the result.
daviddlhz@LAPTOP-8746PFEQ:~$ whereis cd cd: daviddlhz@LAPTOP-8746PFEQ:~$
And we note that it does not return anything this is because of the above mentioned that it is an internal function of our shell.
Current directory.
If the shell does not find the command in the aliases or built-in ones the following would be valid if we are actually passing it a path or where our executable is located or if it is within our current directory.
for example if we place the command . /script we know that . /script is not an alias and neither is a linux command then what the shell does is
search within our directory.
daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$ ls AUTHORS concat_path. c getline. c path_get. c shell. c README.md exec_program. c hsh prompt. c shell. h builtins. c functions. c man_1_simple_shell script split_buffer. c daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$ . /script This is a script daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$
Script is an executable that I have in my current working directory and as we can see my shell runs it without further complication.
And finally the path.
PATH:
When we enter a terminal, by default we found at home whose route is:
/home/user
(We can get the absolute path with the command pwd which means print work directory)
If we type some command for example "ls" (lists my files and directories) what my shell does internally is to look for a program or executable file that is binary.
Now as you know the operating system where that executable program is?
The PATH is an environment variable.
Environment variables contain information that is accessed through the variable name (just like in programming languages).
For example:
HOME is an environment variable and we can check it as follows:
$ echo $HOME /home/user
(this means we are making a call to this integer variable)
Now as we know we have that contains our PATH we simply call our integer variable:
$PATH $ echo $PATH
We can also obtain the environment variables for this we can use these commands env or printenv.
$env OR $printenv HOSTTYPE=x86_64 LESSCLOSE=/usr/bin/lesspipe %s %s LANG=C.UTF-8 WSL_DISTRO_NAME=Ubuntu-18.04 USER=daviddlhz PWD=/home/daviddlhz HOME=/home/daviddlhz NAME=LAPTOP-8746PFEQ XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop SHELL=/bin/bash TERM=xterm-256color SHLVL=1 LOGNAME=daviddlhz PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Program Files/WindowsApps/CanonicalGroupLimited.Ubuntu18.04onWindows_2020.1804.7.0_x64__79rhkp1fndgsc:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath:/mnt/c/Program Files (x86)/Intel/TXE Components/TCS/:/mnt/c/Program Files/Intel/TXE Components/TCS/:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/Program Files (x86)/Common Files/lenovo/easyplussdk/bin:/mnt/c/Program Files/Intel/TXE Components/DAL/:/mnt/c/Program Files (x86)/Intel/TXE Components/DAL/:/mnt/c/Program Files/Intel/TXE Components/IPT/:/mnt/c/Program Files (x86)/Intel/TXE Components/IPT/:/mnt/c/Program Files/PuTTY/:/mnt/c/HashiCorp/Vagrant/bin:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/dotnet/:/mnt/c/Users/DavidDlhz/AppData/Local/Microsoft/WindowsApps:/snap/bin
these variables return a list of all the environment variables we have, some of them are:
SHELL=/bin/bash (the type of shell in use) TERM=xterm (the default terminal program) USER=pepito (the username) PWD=/home/pepito (the default path of the user) LANG=es_ES.utf8 (the language character set) DESKTOP_SESSION=xfce (the desktop environment) PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin (the PATH)
The PATH is perhaps the most important environment variable.
The PATH informs the shell (in most cases BASH) where the programs are located
binaries that I can run on the system, without having to call them by their absolute path(/bin/pwd).
If in the end our shell does not find the command simply send an error message for example:
daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$ xrx Command 'xrx' not found, did you mean: command 'xdx' from deb xdx command 'xx' from deb fex-utils command 'rx' from deb lrzsz command 'x2x' from deb x2x command 'rxrx' from deb libregexp-debugger-perl command 'xr' from deb crossroads
Try: sudo apt install deb
daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$ /xrx -bash: /xrx: No such file daviddlhz@LAPTOP-8746PFEQ:~/simple_shell$
Now knowing how our shell works when to search and where it searches and what it does in every search.
we can say that when we execute the command ls -l (which is found in the path) we are actually running ls but with the difference that to that executable we are passing -l which really means long format.
This way we can see how the prompt works.
Now as we know what process the command interpreter does to know which is a valid command or not, where it searches?
Well the shell first looks for the command in its alias list. If it does not find it,
searches for it in its internal commands. If it does not find it, it looks for it in the list of functions that have been defined. Finally,
if you don’t find it either, look for an external command using the PATH variable.
ALIAS IN LINUX
Aliases are used to rename a command, making it easier to use many commands with just one type
for example:
daviddlhz@LAPTOP-8746PFEQ:~$ alias displaylongformat='ls -l' daviddlhz@LAPTOP-8746PFEQ:~$ displaylongformat total 24 -rw-rw-rw- 1 daviddlhz daviddlhz 17 Mar 30 10:00 ' [ ' '"Holberton School" ' '' '' ' **$ ? * * * **:)"' -rwxrwxrwx 1 daviddlhz daviddlhz 8344 Mar 30 10:30 a.out -rwxrwxrwx 1 daviddlhz daviddlhz 8528 Apr 5 00:26 axc -rw-rw-rw- 1 daviddlhz daviddlhz 296 Apr 5 00:23 axc. c drwxrwxrwx 1 daviddlhz -rw-rw-rw- 1 daviddlhz daviddlhz 271 Mar 30 10:30 main. c drwxrwxrwx 1 daviddlhz daviddlhz 4096 Apr 9 -rwxrwxrwx 1 daviddlhz daviddlhz 25 Mar 30 10:58 script drwxrwxrwx 1 daviddlhz daviddlhz 4096 Apr 16 15:14 daviddlhz@LAPTOP-8746PFEQ:~$
Consulte los diccionarios Collins y Reverso
A way to do this task is type:
/home/roberto/report$ ls - 1993-1 1994-1 data1 data5 1993-2 data-new data2 /home/roberto/report$ mkdir ~/backup /home/roberto/report$ cp data* ~/backup /home/roberto/report$ ls -F ~/backup data-new data1 data2 data5 /home/roberto/report$
As you can see, the asterisk (*) tells cp to take all the files that start with data and copy them to /backup
What really happen?
In fact, there are a couple of special characters intercepted by the shell, bash. The character "*", asterisk, says "change this word with all files that meet this specification". Thus, the command "cp data* /backup", like the one above, changes to "cp data- new data 1 data 2 data 5 /backup" before executing it.
To illustrate this, I will introduce a new command, echo. echo is an extremely simple command; repeat, or display, any parameter. In this way:
/home/roberto$ echo Hello! Hello! /home/roberto$ echo How are you? How are you? /home/larry$ cd report /home/roberto/report$ ls -F 1993-1 1994-1 data1 data5 1993-2 data-new data2 /home/roberto/report$ echo 199* 1993-1 1993-2 1994-1 /home/roberto/report$ echo *4* 1994-1 /home/roberto/report$ echo *2* 1993-2 data2 /home/roberto/report$
Sometimes, type a long command to bash and, before pressing | _Intro_ | realizes that you have made an error writing it. You can just erase everything and retype correctly, but it's too much effort! Instead, you can use the arrows to move, delete the incorrect character (s), and type the information correctly.There are many special keys that help edit the command line, many of them similar to the commands used in GNU Emacs. For example, | _C-t_ | swap two adjacent characters.
Another peculiarity of bash is the automatic execution of command lines. For example, let's look at the following example of a typical cp command:
/home/roberto$ ls -F this-is-a-long-file /home/roberto$ cp this-is-a-long-file long /home/roberto$ ls -F short this-is-a-long-file /home/roberto$
It is a great inconvenience to have to type each letter of this-is-a-long-file every time you want to access it, the same happens if we want to create this-is-a-long-file by copying / etc / passwd2 into it . Now, we will learn to write the previous cp command faster and with less possibility of error.
Instead of typing the name of the entire file, write "cp es", press and release the | _Tab_ | key. The rest of the file name magically appears on the command line, and can be written short. Unfortunately, bash couldn't read the thoughts, so it must be typed short.
When you press | _Tab_ |, bash looks at what's written and looks for a file that starts like that. For example, if I type / usr / bin / ema and then press | _Tab_ |, bash will find / usr / bin / emacs since it is the only file that starts with / usr / bin / ema on my system. Instead, if I type / usr / bin / ld and hit | _Tab_ |, bash will warn me. That's because three files, / usr / bin / ld, / usr / bin / ldd, and / usr / bin / ld86 start with / usr / bin / ld on my system.
If a completion is attempted and bash warns, you can immediately press | _Tab_ | again to get a list of all the files matching the pattern. In this way, if you are not sure of the exact name of the file, we can type the first characters of the name and search for it in a smaller list of files.
A very important aspect of Unix is the ability to redirect the output. This allows us, instead of seeing the results of a command, to save them in a file or send them directly to a printer. For example, to redirect the output of the command "ls / usr / bin", a ">" sign is placed at the end of the line, and the file where to leave the output is indicated:
/home/roberto$ ls /home/roberto$ ls -F /usr/bin > list /home/roberto$ ls list /home/roberto$
As you can see, instead of writing the names of all the files, the command creates a totally new file in the current directory. Let's take a look at this file using the cat command.
If you remember, cat was a pretty useless command that copied what was written (standard input) to the terminal (standard output). cat also prints a file on standard output if the file is indicated as a parameter:
Regardless, cat does some cool stuff when its output is redirected. What does the command "cat listing> file" do? Normally, the "> file" says "take all the command output and put it in file". The output of the "cat listing" command is the listing file. So we have invented a new (and not so efficient) method of copying files.
What happens to the command "cat> fox"? cat reads each line written to the terminal (standard input) and prints it back (standard output) until it reads | _Ctrl-d_ |. In this case, the standard output has been redirected to the fox file. Now cat serves as a rudimentary editor:
/home/roberto $ cat> fox The quick brown fox jumps on the sloppy dog. press Ctrl-d
Now the fox file has been created containing the phrase "The quick brown fox jumps on the sloppy dog". One last use of the versatile cat command is to concatenate files. cat will print each file given as a parameter, one after the other. The command "cat fox listing" will print the listing from the / usr / bin directory, and then the silly phrase. Thus, the command "cat listing fox> listy zorro" will create a new file containing the contents of listing and fox.
Multitask
Job control refers to the ability to put processes (essentially another word for programs) in the background and put them back in the foreground.
This is like saying that you want to be able to execute something while doing other things, but to be there again when you want to say something or stop them. On Unix, the main tool for process control is the shell, it will keep track of the processes for you, if you learn how to speak their language.
The two most important words in that language are fg, for the foreground, and bg, for the background. To understand how they work, use the yes command at the command prompt.
/home/roberto$ yes
This has the wonderful effect of moving a long column of yes around the left side of the screen, so fast that they cannot be followed5. To stop it, you could press | _Ctrl-c_ | and kill it, but this time you will press | _Ctrl-z_ |. It seems to have stopped, but there will be a message before the system prompt, more or less like this:
[1] + Stopped yes
There are good reasons for this strange command to exist. Certain commands wait for a confirmation, a "yes" ([and] is in English) to a question. The yes command allows the programmer to automate the answer to those questions.
It means that the yes job has been suspended in the background. It can be made to continue running by typing fg at the command prompt, which will bring it to the foreground again. If desired, other things can be done earlier, while suspended. Try a few ls or something before bringing it to the fore again.
Once you have returned to the foreground, the yes will begin to come out again, as fast as before.
No need to worry that if you have "stored" more yess while on hold to send them to the screen: when a job is suspended, the entire program does not run until it is brought back to life. (Now press | _Ctrl-c_ | to really kill him.)
Let's put aside the message we got from the shell:
[1] + Stopped yes
The number in square brackets is the job number for this process, and will be used when specifically referenced. (Naturally, from the moment we have multiple jobs running, we need a way to access each one). The following "+" indicates that this is the "current job," that is, the most recent process that has been moved from the foreground to the second.
Typing "fg" would put the job with the "+" in the foreground again. (More on this later, when discussing running multiple jobs at once.) The word Stopped means that work is "stopped". The job is not dead, but is currently not running. Linux has put it in a special suspended state, ready to jump into action when someone requests it. Finally, yes is the name of the job that was stopped.
Before we go any further, let's kill this job and start it differently again. The command is called kill and is used as follows:
/home/roberto$ kill% 1 [1] + Stopped yes /home/roberto$
That message about the process indicating "stopped" again is misleading. To find out if it's still alive (that is, both running and frozen in a suspended state), type "jobs":
/home/roberto$ jobs [1] + Terminated yes /home/roberto $
Now you know: the job is done! (The jobs command may not display anything, which simply means that there are no jobs running in the background. If a job has just been killed, and typing jobs displays nothing, you can be sure that the kill command will has run successfully (it will normally indicate that the job has "finished").
Now run yes again, like this:
/home/roberto$ yes> /dev/null
If you read the section on input and output redirection, you know that the output of yes is being sent to a special file called / dev / null. / dev / null is a black hole that eats whatever output is sent to it (you can imagine that torrent of yes coming out from behind the computer and punching a hole in the wall, if that makes you happy).
After typing this, the prompt will not be retrieved, but that yes column will not appear either. However the output is being sent to / dev / null, the job is still running in the foreground. As always, it can be suspended by pressing | _Ctrl-z_ |. Do this now to return to the system prompt.
/home/roberto$ yes> /dev/null ["yes" is executed, and only Ctrl-z has been pressed] [1] + Stopped yes> /dev/null /home/roberto$
Is there any way to run it in the background, while leaving the command prompt to work interactively? The command to do that is bg:
/home/roberto$ bg [1] + yes> /dev/null & /home/roberto$
Fork/ Execve/ Wait
Fork
#include unistd. h>
Fork() is a system call with which we can create new processes in the system.
fork() will cause the system to create a copy of the original process (then called parent) so that the two processes follow their paths independently. The new process, called son, has a new PID.
The PPID (parent’s PID) will be that of the process that has called fork(): the parent process.
The system call fork gives us a value that is a PID (Process Identifier) that can be:
greater than 0 (referring to the parent), zero (referring to the child), less than 0 (which indicates that there was an error and the process could not be created)
For example:
if(fork() > 0) { printf("I am the process father"); } else if(fork() == 0) { printf("I am the process father"); } else if(fork() 0) { printf("Error: Not created the process"); }
execve
#include unistd. h>
execve() is a system call that allows you to execute processes.
It allows us to execute commands, although it does not allow us to save the output of the command in a variable.
If execv() returns some value, execv() had an error.
For example, this system call receives three parameters:
FILENAME: Which may be the name or path of our file (This file must be a binary executable or a shell script that starts with the symbols!#).
ARGV: An array of string arguments passed to the new program.
ENVP: Which is an array of key-type argument strings=value (This argument represents the environment variables).
int execve (const char *filename, const char *argv [], const char *envp[]);
In case of success this function does not return any value but when it has no success it returns -1, when we use this system call and has successful response (Osea does not return any value) automatically replaces or transforms the process where we are making the call, makes the call and does not return where he was called.
Wait
#include sys/types. h>
#include sys/wait. h>
The system call wait is used to suspend a process until another process finishes or changes status.
pid_t wait(int *status);
In this system call we can use wait to wait for a child process to finish before the parent process because if the parent finishes first that the son will have zombie or orphan processes that are processes that do not have a parent and therefore will remain consuming resources of our system, that is why this function is very important as it prevents a workflow from getting out of control.
For example:
int main(void) { pidut child_pid; internal status; child_pid = fork(); if (child_pid == -1) { perror("Error:"); return (1); } if (child_pid == 0) { printf("Wait for me, wait for me"); sleep(3); } else { wait(&status); printf("Oh, it’s all better now n"); } return (0); }
In this example the parent process will wait for 3 seconds of the process.
if not simply by its executable name command which in this case is pwd.
Here we have finished a summary of what happens when in a terminal we type ls -l I hope it helps you and if you have any questions please let me know by this means.
This blog was made thanks to my partner David De La Hoz Cohort 11 at Holberton Barranquilla in which we were able to make the Shell.
Thank you so much for everything.
Experienced Full-Stack Developer | Building Scalable Web Apps with React, Next.js, SvelteKit, & NestJS
4 年Great post!
Logistic Manager en City Lending Inc
4 年Cool