Over the past 18 or so recent years of my heavy use of shells and command line and terminal-first tools like vim and tmux and really making an effort to (and largely succeeding in) editing code through a terminal emulator, I've become pretty familiar with the de-facto conventions and intricacies present in the unix command line interface and terminal emulation.
What you are going to use the command line with is a terminal emulator. The reason this is called a terminal emulator and not just a terminal, is because a terminal refers to an old-timey CRT computer monitor gadget that has a bit of a little dumb computer built into it that is designed to talk to the real actual computer. this terminal device talks to the real computer with a serial connection of some sort and they are exchanging strings. When the computer replies the terminal is translating the string to print characters on the screen. Remember, back in the 1960s or whenever it was (that'd be when my dad was a kid) that people were coming up with this stuff, the computers were not very powerful, and GUIs were 20 years in the future and the only way that anyone could fathom interacting with computers was to make them look and work like high tech typewriters.
Indeed one of the things that you'll pick up on fairly early on when delving into terminal emulation is the notion of "VT100 compatibility". It is informative to know that the DEC VT100 is a model of hardware terminal introduced in 1978.
Anyway back to the future present, where a terminal emulator is what you're going to be using. On any of the big three operating systems in use today, you actually get a terminal emulator out of the box with the operating system:
cmd.exe
, which is also still
available to you as wellThe job of the terminal emulator is to handle the logic that was built into the ancient computer terminals: it facilitates communication between the terminal (read: textual) computer program and the user (by rendering text to the screen) using what are fundamentally just strings of characters. Often these interfaces are referred to as streams, because there is no fixed, limited length of the string. It is important to be able to, when necessary, have programs that can consume input and produce output of indefinite length.
Since actual hardware terminals haven't been a thing since late 1970's, for the past almost 50 years terminal work has been done largely on terminal emulators. It's essentially all you need to use a modern GUI computer to make use of terminal programs and applications.
The other piece of software that you will be using with the command line is a program referred to as a shell. The common
example of this is bash
whose full name is "Bourne Again SHell". The shell I daily drive is called zsh
, which also happens to be the default nowadays on macOS; functionally it is very similar to bash. On a Linux distro you will generally find bash preinstalled.
The exception here is Windows will not bundle a UNIX shell by default, since Windows definitely isn't UNIX in a vastly more
significant meaning of "isn't" than GNU is(n't).
Now, the purpose of the shell is to provide the actual command line interface. The meaning here may not be obvious in the abstract, but it's probably important to highlight: Some piece of software has to be responsible for each of the interactions that takes place. We have covered already the function of the terminal emulator, which is to consume textual input and render it out to a screen for the benefit of your eyeballs. It also manages a buffer so that the text that was previously sent out by a terminal program continues to be visible. It also generally provides scrollback buffer, so that even once the data scrolls off the top of the screen you are able to scroll up to review it. The terminal emulator also is responsible for handling input so you can type on the keyboard when its window is focused in a GUI OS to capture the keystrokes so they can be sent to the terminal program. That is all the terminal does and therefore is all a terminal emulator will do.
I will also take this opportunity to point out that you can run an OS like Linux in "framebuffer terminal mode", which means no GUI window management system is running, and you will be presented with a terminal interface where you type your login. When you have a computer running in this mode, you will notice in contrast with the use of a typical terminal emulator app that you have no mouse available to you. You're not able to switch between the terminal and a separate graphical application or "desktop", because in this mode the barebones linux framebuffer terminal (emulator) is ALL you're running! This is also the default mode that a distro like Ubuntu Server will be set up in.
Given that the terminal (emulator) only handles text rendering and keyboard input handling, something else has to provide the actual logic around executing commands on the command line, and that is the responsibility of the shell. It's just called a shell because it's a program or command on its own, just like any other terminal program or command, but it's a special one that is designed to be the interface from which you interact with the computer.
You can think of a shell as implementing a basic while loop. It will print a command line prompt, traditionally $
for
bash, to give you a terse indication that the system is ready to accept a command.
As you type into the shell the shell will echo the same keystrokes back and the shell will also handle logic such as deleting a character when you type backspace or ctrl+h for example. This is because the terminal once again will only emit verbatim the keycode of the keystroke into what's running inside, so it's important to understand the distinction that the shell is the one performing logic on the currently-being-edited command prompt string based on the keystrokes coming in.
When you press enter on your keyboard (which the terminal will translate into a single carriage return ascii character to send into the shell process's stdin stream), the shell will attempt to execute the command prompt string that you have constructed and interpret it as a command. Here the shell will generally use simple rules to evaluate the first word you typed as a command and all subsequent words as command line arguments to the program. It is interesting to note that this is a convention that has persisted for nearly 70 years. It's very natural, it's a primitive language that always has the same format, a verb followed by arguments to specify in more detail what you want. In most programming languages you will note the existence of built in handling of "command line parameters" with variables named argc and argv. For example a C or C++ program is always written in such a form:
int main(int argc, char*[] argv) {
return 0;
}
It is through this default main function interface that we can access the command line parameters for the program.
Often when we work with a GUI application, these values are not used or are used for configuration purposes, but you can see how natural and standard this interface is. If you were wondering why programs always have these weird parameters to the main entry point, now you know.