% The Linux command-line --- subtitle: WTF is Linux --- [back](index.md) ## Purpose The main purpose of the command line is to execute other programs using a text only interface. While "program" in a broader context might imply a user interface with a separate window, buttons, etc., what I mean here is a program that only outputs text for us to see. While the command-line was mostly created because historically, computers weren't quite powerful[^teletypewriter], it's still used to this day by a large amount of people for various reasons (some people find it handy, clearer, faster, or even more elegant). [^teletypewriter]: It's also likely that it was created is because computers didn't even have screens before, but instead [printed text on paper](https://en.wikipedia.org/wiki/Teleprinter). [Example](https://spacepub.space/videos/watch/d8943b2d-8280-497b-85ec-bc282ec2afdc). [Other example with older machine](https://www.youtube.com/watch?v=2XLZ4Z8LpEE). ## Usage When you open a terminal, you will be greeted by a prompt that will kindly "ask" you to input a command. A command is composed of a command name (or verb), and 0, 1, or more arguments. The verb and each argument are separated by 1 or more spaces. Just like in English grammar, the arguments have different meanings for different verbs. For example, when you use the verb `cp` (for "copy"), the first arguments are the "source" (that is, the files to copy), and the last argument is the destination: ```bash # Copies the file "file_1.txt" into "file_2.txt" user@host:~$ cp file_1.txt file_2.txt # ^^ ^^^^^^^^^^ ^^^^^^^^^^ # | | | # | '-------------'- arguments # | # '---------------------- command name (verb) ``` But when you use the verb `mkdir` (for "make directory"), all the arguments are names of directories that you want to create: ```bash # Create the directories "dir_1", "dir_2", and "dir_3" user@host:~$ mkdir dir_1 dir_2 dir_3 ``` For any new commands you learn, be sure to check the manual by executing the command `man `. For example, if you want to know more about the `mkdir` command, you simply have to execute: `man mkdir`. ## Argument conventions If you are developing a new command-line program, you are free to do anything you want with the arguments that are passed down to you. Should you wish it, you could make a program that goes like this: ```bash # Copies the file "file_1.txt" into "file_2.txt" user@host:~$ my_cp ~~file_1.txt//file_2.txt~~ # Copies the file "file_1.txt" into "file_2.txt" # and overwrite "file_2.txt" if it exists user@host:~$ my_cp ~~file_1.txt//file_2.txt~~ _~overwrite ``` But that would be pretty horrible. More than the fact that this syntax is hideous, we need a common syntax to specify options, flags, etc. And this is where the POSIX convention, and the GNU convention comes in. It specifies that optional arguments are to be prefixed by `--`, or `-` if it is just one letter: ```bash # Copies the file "file_1.txt" into "file_2.txt" # and overwrite "file_2.txt" if it exists user@host:~$ cp file_1.txt file_2.txt --force # Copies the file "file_1.txt" into "file_2.txt" # and overwrite "file_2.txt" if it exists (using the short option) user@host:~$ cp file_1.txt file_2.txt -f ``` Some options can also take themselves an argument, by separating them with a `=`, or just using the following command-line argument: ```bash # Lists file in the current directory, sorted by size user@host:~$ ls --sort=size # Same thing user@host:~$ ls --sort size ``` Options without an argument are commonly called "flags." Again, these are still conventions, developers are free to ignore those. To this day, you can still find programs that don't respect either the POSIX nor the GNU conventions. TODO: link to example with https://explainshell.com ## Components While using the term "command-line" might suggest that it's composed of a single component, it isn't. Should you have a problem to debug, I always find it useful to know how the different pieces interact with on another. So, here are the different pieces that are the most useful to us[^tty]: [^tty]: Some components are omitted for simplicity's sake, like the concept of "tty," "pty," and others The terminal / terminal emulator : Renders text on the screen The prompt / REPL : A part of the shell that interactively asks for command-lines, and shows you some information like what user you are logged as, what directory you're currently in, etc. The shell : Interprets command-lines and execute them ### The terminal As I said above, the terminal (or terminal emulator) is the program that renders the text on the screen. It's therefore *not* the kind of program I was talking about in the [purpose] section. It's a graphical program that creates a new window, runs a text-only program as a child process, and for each character outputted by the text program, convert the character into pixels that are rendered in the window for our eyes to see. Therefore, if you want to change the font displayed, the terminal is the program to configure. "But what kind of child program does the terminal starts?" you might ask. And that brings us to: ### The prompt While a terminal emulator is able to run any kind of program, it would be most useful if it started a program that repeatedly would take a command-line and execute it. It would be a pain to start a terminal emulator for each and every little commands we wanted to execute[^close-on-exit]. [^close-on-exit]: In fact it's so common to run a prompt in a terminal emulator that most terminal just closes the window and exit when the text program exits. If you were to run `mkdir new_dir` as the terminal command, you would see a new window being created, and it would close after ~0.002 seconds. And this is why we run an interactive text program: it's just easier, faster, and way less annoying. When you first start a terminal in a new installation of a Linux system, you will mostly likely be greeted with a Bash prompt, Bash being the name of one of the several shells that exists in this world. Your prompt will likely resemble this (annotations added): ```bash # ,------ username you are logged in as # | # | ,---- directory you are in, # | | '~' means your user directory # vvvv v user@host:~$ # ^^^^ ^ # | | # | '--- '$' if you are a normal user, # | '#' if you are the root user # | # '--- name of the machine you are on ``` But just like everything is in the UNIX world, it's very customizable: - You can for example run a prompt from a different shell: instead of using the Bash prompt, you can use the one from Zsh, Fish, Csh, Nushell, etc. - You can customize the prompt itself using the configuration system of Bash, Zsh, etc. For example in Bash and many other shells, you can change your prompt by changing the `$PS1` variable. Try executing this in a Bash shell (you may need to launch `bash --norc` before): ```bash PS1='\A \u@\h \w (\s) \$ ' ``` Full documentation of the prompt's "special characters" [here](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Controlling-the-Prompt). ### The shell It might seem like the prompt is everything there is about Bash, Zsh, etc., but these programs are actually much more powerful than that: a shell is a full-size programming language! Like any programming language it's very useful for automating tasks, and the fact that a shell script (a program written in a shell language) is included in every Linux system, and that it's very quick to write makes it very common in embedded systems and system administration. So, let's go over the particularities of the shell programming language. TODO: move these sections to new "Shell Scripting" article #### Basic interpretation of a command ```c #include /// The entry point of the program. /// /// \param argc the number of command line arguments /// \param argv the command line argument, /// as an array of NULL terminated strings int main(int argc, char** argv) { for(int i = 0; i < argc; ++i) { printf("Argument %i: %s\n", i, argv[i]); } } ``` #### Variables and interpolation TODO #### Control flow TODO #### The various shell implementations TODO ## Further reading TODO