avatarTom Deneire

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

6088

Abstract

ef="https://en.wikipedia.org/wiki/%22Hello,_World!%22_program">“Hello, World!”-program</a>, for instance:</p><div id="a3c0"><pre><span class="hljs-built_in">echo</span> <span class="hljs-string">"Hello, World!"</span></pre></div><p id="6677">Using a shell, though, implies knowledge of the shell commands (and syntax, but that’s beyond the scope of this article). Some of these may vary according to the shell flavor you are using, but a wide range of commands are guaranteed on every Unix system by the <a href="https://en.wikipedia.org/wiki/Single_UNIX_Specification">Single UNIX Specification</a>.</p><p id="de15">So let’s have a look at some of these commands.</p><h2 id="58ee">Filesystem</h2><p id="f254">The first set deals with navigating and manipulating the filesystem. Common commands are:</p><ul><li><code>cd</code> (change directory)</li><li><code>ls</code> (list files or directories)</li><li><code>mv</code> (move),<code>cp</code> (copy) and <code>rm</code> (remove)</li><li><code>cat</code> (print file content)</li></ul><p id="ba09">For example:</p><div id="68d5"><pre><span class="hljs-variable"></span> <span class="hljs-built_in">cd</span> tmp</pre></div><div id="099e"><pre>~/tmp <span class="hljs-built_in">cd</span> Medium</pre></div><div id="7c30"><pre>/tmp/Medium <span class="hljs-built_in">ls</span> hello_world.sh</pre></div><div id="6703"><pre>~/tmp/Medium <span class="hljs-built_in">cat</span> hello_world.sh <span class="hljs-built_in">echo</span> <span class="hljs-string">"Hello, World!"</span></pre></div><h2 id="a9b5">Redirection</h2><p id="4fd8">You see that the output of these commands is printed in the terminal. Technically, we say that when a command is executed via an interactive shell, the computer’s <a href="https://en.wikipedia.org/wiki/Standard_streams">standard streams</a> are connected to the text terminal on which the shell is running. These three input/output (I/O) connections are called standard input (“stdin”), standard output (“stdout”) and standard error (“stderr”).</p><p id="0cca">The neat thing, however, is that the shell allows you to redirect these streams with these operators:</p><ul><li><code>|</code> (pipe output to another command)</li><li><code><</code> (redirect input)</li><li><code>></code> (redirect output)</li></ul><p id="bfe3">Like so (using the content of <code>hello world.sh</code> as input for the Shell interpreter <code>sh</code>)</p><div id="3f8c"><pre><span class="hljs-regexp">/tmp/</span>Medium<span class="hljs-variable"> </span>sh &lt; hello_world.sh Hello, World!</pre></div><p id="7514">Another way to do the same is to pipe the content of <code>hello world.sh</code> to<code>sh</code> :</p><div id="57a7"><pre>~/tmp/Medium <span class="hljs-keyword">cat</span> hello_world.<span class="hljs-keyword">sh</span> | <span class="hljs-keyword">sh</span> Hello, World!</pre></div><p id="731e">The resulting output can then be redirected to a file (<code>myresult.txt</code>)</p><div id="444f"><pre><span class="hljs-regexp">/tmp/</span>Medium<span class="hljs-variable"> </span>sh &lt; hello_world.sh &gt; myresult.txt ~<span class="hljs-regexp">/tmp/</span>Medium<span class="hljs-variable"> </span>cat myresult.txt Hello, World!</pre></div><h2 id="991d">Searching</h2><p id="3920">Searching the filesystem can be done with commands like <code>find</code> , for instance find all <code>.tmp</code> files recursively, i.e. in the present directory (<code>.</code>) and its subfolders:</p><div id="48e5"><pre>~/ find . -<span class="hljs-keyword">type</span> f -<span class="hljs-keyword">name</span> <span class="hljs-string">'*.tmp'</span></pre></div><p id="cd8c">Another classic is <code>grep</code> which allows you to search text files or streams for lines that match a <a href="https://en.wikipedia.org/wiki/Regular_expression">regular expression</a>:</p><div id="cf9a"><pre> <span class="hljs-keyword">find</span> . -type f -name <span class="hljs-string">'.tmp'</span> | <span class="hljs-keyword">grep</span> <span class="hljs-string">"dropbox"</span> .<span class="hljs-regexp">/.dropbox/</span>logs<span class="hljs-regexp">/1/</span><span class="hljs-number">1</span>-a186-<span class="hljs-number">604</span>bb260.tmp .<span class="hljs-regexp">/.dropbox/</span>logs<span class="hljs-regexp">/1/</span><span class="hljs-number">1</span>-f683-<span class="hljs-number">604</span>bb261.tmp .<span class="hljs-regexp">/.dropbox/</span>logs<span class="hljs-regexp">/1ro/</span><span class="hljs-number">1</span>-<span class="hljs-number">67</span>bf-<span class="hljs-number">5</span>e0d9feb.tmp</pre></div><h2 id="0305">Text processing</h2><p id="786f">Besides <code>grep</code> there are many other Unix utilities for text processing, some of which are programming languages on their own like <a href="https://en.wikipedia.org/wiki/AWK"><code></code>AWK</a>or <a href="https://en.wikipedia.org/wiki/Sed"><code></code>sed</a>. Some of the more straightforward commands are:</p><ul><li><code>wc</code> (word or line count)</li><li><code>head</code> and <code>tail</code> (display the beginning/end of a file)</li><li><code>more</code> (view the contents of a file one page at a time)</li></ul><h2 id="1f97">Other</h2><p id="4345">Other utilities include listing active processes and interrupting them with <code>ps</code> and <code>kill</code> respectively, or an interface to the documentation of Unix commands with <code>man</code> . (Just try <code>man ps</code> , for instance). Most commands also support the flag <code>--help</code> , like so:</p><div id="316a"><pre><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">ls</span> --<span class="hljs-built_in">help</span> | <span class="hljs-built_in">head</span> --lines=3</span></pre></div><div id="8255"><pre>Usage: ls [OPTION]... [FILE]... List information about <span class="hljs-keyword">the</span> FILEs (<span class="hljs-keyword">the</span> current <span class="hljs-built_in">directory</span> <span class="hljs-keyword">by</span> default). Sort entries al

Options

phabetically <span class="hljs-keyword">if</span> <span class="hljs-literal">none</span> <span class="hljs-keyword">of</span> -cftuvSUX nor <span class="hljs-comment">--sort is specified.</span></pre></div><p id="4e4e">And of course, there is a plethora of other CLI applications out there, just waiting for you to install and use them alongside the standard utilities.</p><h1 id="6b37">Unix philosophy</h1><p id="593b">Now that we are familiar with some Unix commands, we can return to our main question. Given the learning curve and lack of visual appeal, why do developers prefer a CLI over GUIs?</p><p id="b318">If you consider the above examples, you’ll notice that they share a common perspective, a basic idea about how software should work. We call this the <a href="https://en.wikipedia.org/wiki/Unix_philosophy"><b>Unix philosophy</b></a><b>,</b> based on the experience of leading developers of the Unix operating system. It advocates minimalist, modular software development, and is often summarized as follows:</p><ol><li>Write programs that do one thing and do it well.</li><li>Write programs to work together.</li><li>Write programs to handle text streams, because that is a universal interface.</li></ol><p id="a31b">Let’s take <code>cat</code> as an example. It is a very simple command that prints a text file’s content to standard output. However, it is excellent at its job; offering no small amount of options like numbering the output lines, suppressing empty lines, show non-printing characters, etcetera. Moreover, it can easily be combined with other commands like <code>grep</code> and works well with redirection. For instance, want to filter a bunch of CSV files on a value and save the result?</p><div id="b4b2"><pre><span class="hljs-variable"></span> <span class="hljs-built_in">cat</span> *.cvs | grep <span class="hljs-string">"myvalue"</span> &gt; result.csv</pre></div><p id="94f3">Developing software with such simple, modular, reusable tools indeed leads to understandable, maintainable, elegant code that is extremely powerful to boot.</p><h1 id="5e22">CLI versus GUI</h1><p id="efca">So let’s summarize the advantages of the commands line interface versus its graphical counterpart.</p><h2 id="6ca7">Efficiency</h2><p id="3099">First of all, graphical user interfaces lack the efficiency of the command line. Applying commands to multiple files, combining commands or even writing full-fledged Shell scripts allow for a much more efficient way to do things. Let’s say I want to scan my computer for JPEGs and move them all to one folder:</p><div id="171c"><pre><span class="hljs-meta prompt_">~/ </span><span class="language-bash">find . -<span class="hljs-built_in">type</span> f -name <span class="hljs-string">'*.jpeg'</span> -<span class="hljs-built_in">exec</span> <span class="hljs-built_in">mv</span> -t myfolder {} +</span></pre></div><p id="f0d7">Good luck doing that with Finder or Windows Explorer!</p><p id="bdd4">(A tip for understanding more complex commands like the one above: you can have them analysed by a tool like <a href="https://www.explainshell.com/explain?cmd=find+.+-type+f+-name+%27*.jpeg%27+-exec+mv+-t+myfolder+%7B%7D+%2B">explainshell.com</a>!)</p><h2 id="c207">Consistency</h2><p id="8bf7">Apart from being efficient, the command line is also very consistent. GUIs come and go, their interfaces change, but terminals and shell commands stay the same. This means that I can execute the same commands and shell code I know from my laptops (Linux Mint and Ubuntu), in the shell of my <a href="https://www.raspberrypi.org/">Raspberry Pi</a>, which I use as a home server, or in the shell of my company’s development and production servers, which run RHEL.</p><h2 id="9741">Necessity</h2><p id="b1e3">When it comes to servers, it is clear that using GUIs is just not an option. No one in my team even has physical access to our company’s servers! And besides, there is no regular display or other I/O hooked up to them. All server access goes through a cryptographic network protocol called <a href="https://en.wikipedia.org/wiki/SSH_(Secure_Shell)">SSH</a>, which is short for … “Secure Shell”.</p><p id="6bde">Moreover, whenever you need to start a process, execute a script or an executable from within a programming language, this is also impossible without the shell. In Python, for instance, one way to do this is with <code>os.system()</code> or with <code>os.popen()</code> which returns stdout, like this:</p><div id="a4d7"><pre>import <span class="hljs-built_in">os</span> result = <span class="hljs-built_in">os</span>.<span class="hljs-built_in">popen</span>(<span class="hljs-string">'ls -la'</span>).<span class="hljs-built_in">read</span>() <span class="hljs-built_in">print</span>(result)</pre></div><h2 id="8396">Text</h2><p id="cf53">One final advantage of using the shell is the fact that it is a text interface. At first this might seem as a drawback to GUIs, but it is actually an incredible benefit. Text commands can be saved, which makes them shareable and reproducible. Imagine a friend coming to you for help saying “I did something in Finder and now my Documents folder is gone!”, compared to him being able to enter <code>history</code> into the terminal and give you a complete list of all commands leading up to the problem…</p><h1 id="2242">Conclusion</h1><p id="a463">Being familiar with shell commands and using a terminal emulator are indispensable skills for any software developer. They offer quick and dependable access to highly complex commands that are difficult or even impossible to execute using graphical applications.</p><h1 id="77f8">More information</h1><p id="1213">You can read more about this subject in the amazing GitHub repo:<i> </i>T<a href="https://github.com/jlevy/the-art-of-command-line">he Art of the Command Line</a></p><p id="1395"><i>Hi! </i>👋 <i>I’m Tom. I’m a software engineer, a technical writer and IT burnout coach. If you want to get in touch, check out <a href="https://tomdeneire.github.io/">https://tomdeneire.github.io</a></i></p></article></body>

Dev 101: Terminal velocity

In the Dev 101 series I cover some basic concepts of computer programming for a broad audience. I guess it’s the explanation I was looking for myself, when I first started out as a programmer…

Photo by Tracy Adams on Unsplash

Introduction

When you ask a developer to remove a folder from their filesystem, chances are small she will use a file manager and drag and drop that folder to the trash. More often than not, she will simply fire up a terminal window and type a command like so:

~$ rm myfolder/ -r

But why would a developer prefer the terminal’s plain layout and cryptic commands over the appealing design and user-friendliness of a file manager? It’s not even usual for beginning programmers to avoid graphical user interfaces at all costs — depriving themselves deliberately of the “easy way” to do things, in order to master the so-called “command line interface”.

So why is that?

Operating system, terminal and shell

Before we can answer these questions, we need to cover some basics.

Most of us are familiar, at least on an elemental level, with the concept of an operating system (OS). It is a collection of system software that manages both computer hardware and other software. Hardware means that it handles the computer’s input/output-devices, i.e. everything from your keyboard and mouse to the Wi-Fi and display. Software involves managing the computational resources applications can access, scheduling tasks, processor time and memory allocation. The most popular operating systems are Microsoft Windows, macOS and Linux.

Golftheman on Wikimedia Commons

An operating system is made up of different components. Closest to the hardware, is the kernel, the core OS software, which has complete control over everything in the system. Closest to the user, is the shell, aptly named because it is the outermost layer around the operating system.

A shell is a computer program which exposes an operating system’s services to a human user or other programs. Shells provide access to the OS either via a command-line interface (CLI) or a graphical user interface (GUI). The latter is what non-professional computer users are most familiar with; manipulating programs graphically, with operations such as opening and closing windows, and manipulating files like documents on a desk, thus mimicking an “electronic desktop”.

CLI shells are where our terminal comes in. In the early days of computing, a terminal was a separate hardware device that allowed for entering data into a computing system. Nowadays, the word “terminal” actually refers to an emulation of that (hence “terminal emulator”) — a computer interface for text entry and display that can run several kinds of applications, such as a terminal-based editor like vi, or, indeed, a command line interpreter, which is the concrete manifestation of our shell.

Shells come in two different flavors: those for UNIX-like systems, such as Bourne-Again shell (bash), preinstalled on most Linux varieties, and Z shell (zsh, backward compatible with bash), the default shell on macOS since Catalina; and Windows shells on the other hand: cmd.exe (a.k.a. “command prompt”) and PowerShell.

Screenshot of my terminal (GNOME) and shell (Bash) version on Linux Mint 20.1

Unix commands

The remainder of this article will deal with the Unix shell exclusively for two reasons. First, I have little to no professional experience with Windows for software development. Second, even Windows programmers often need to use Unix shell commands because Linux server distributions such as Red Hat or CentOS are very popular.

A UNIX shell is both an interactive command language and a scripting language — in other words, we can use it not only to execute short commands on the command line, but also to write complex script files that can be executed in the same environment or by other software. This is a “Hello, World!”-program, for instance:

echo "Hello, World!"

Using a shell, though, implies knowledge of the shell commands (and syntax, but that’s beyond the scope of this article). Some of these may vary according to the shell flavor you are using, but a wide range of commands are guaranteed on every Unix system by the Single UNIX Specification.

So let’s have a look at some of these commands.

Filesystem

The first set deals with navigating and manipulating the filesystem. Common commands are:

  • cd (change directory)
  • ls (list files or directories)
  • mv (move),cp (copy) and rm (remove)
  • cat (print file content)

For example:

~$ cd tmp
~/tmp$ cd Medium
~/tmp/Medium$ ls
hello_world.sh
~/tmp/Medium$ cat hello_world.sh 
echo "Hello, World!"

Redirection

You see that the output of these commands is printed in the terminal. Technically, we say that when a command is executed via an interactive shell, the computer’s standard streams are connected to the text terminal on which the shell is running. These three input/output (I/O) connections are called standard input (“stdin”), standard output (“stdout”) and standard error (“stderr”).

The neat thing, however, is that the shell allows you to redirect these streams with these operators:

  • | (pipe output to another command)
  • < (redirect input)
  • > (redirect output)

Like so (using the content of hello world.sh as input for the Shell interpreter sh)

~/tmp/Medium$ sh < hello_world.sh 
Hello, World!

Another way to do the same is to pipe the content of hello world.sh tosh :

~/tmp/Medium$ cat hello_world.sh | sh
Hello, World!

The resulting output can then be redirected to a file (myresult.txt)

~/tmp/Medium$ sh < hello_world.sh > myresult.txt
~/tmp/Medium$ cat myresult.txt 
Hello, World!

Searching

Searching the filesystem can be done with commands like find , for instance find all *.tmp files recursively, i.e. in the present directory (.) and its subfolders:

~/$ find . -type f -name '*.tmp'

Another classic is grep which allows you to search text files or streams for lines that match a regular expression:

$ find . -type f -name '*.tmp' | grep "dropbox"
./.dropbox/logs/1/1-a186-604bb260.tmp
./.dropbox/logs/1/1-f683-604bb261.tmp
./.dropbox/logs/1ro/1-67bf-5e0d9feb.tmp

Text processing

Besides grep there are many other Unix utilities for text processing, some of which are programming languages on their own like AWKor sed. Some of the more straightforward commands are:

  • wc (word or line count)
  • head and tail (display the beginning/end of a file)
  • more (view the contents of a file one page at a time)

Other

Other utilities include listing active processes and interrupting them with ps and kill respectively, or an interface to the documentation of Unix commands with man . (Just try man ps , for instance). Most commands also support the flag --help , like so:

$ ls --help | head --lines=3
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.

And of course, there is a plethora of other CLI applications out there, just waiting for you to install and use them alongside the standard utilities.

Unix philosophy

Now that we are familiar with some Unix commands, we can return to our main question. Given the learning curve and lack of visual appeal, why do developers prefer a CLI over GUIs?

If you consider the above examples, you’ll notice that they share a common perspective, a basic idea about how software should work. We call this the Unix philosophy, based on the experience of leading developers of the Unix operating system. It advocates minimalist, modular software development, and is often summarized as follows:

  1. Write programs that do one thing and do it well.
  2. Write programs to work together.
  3. Write programs to handle text streams, because that is a universal interface.

Let’s take cat as an example. It is a very simple command that prints a text file’s content to standard output. However, it is excellent at its job; offering no small amount of options like numbering the output lines, suppressing empty lines, show non-printing characters, etcetera. Moreover, it can easily be combined with other commands like grep and works well with redirection. For instance, want to filter a bunch of CSV files on a value and save the result?

$ cat *.cvs | grep "myvalue" > result.csv

Developing software with such simple, modular, reusable tools indeed leads to understandable, maintainable, elegant code that is extremely powerful to boot.

CLI versus GUI

So let’s summarize the advantages of the commands line interface versus its graphical counterpart.

Efficiency

First of all, graphical user interfaces lack the efficiency of the command line. Applying commands to multiple files, combining commands or even writing full-fledged Shell scripts allow for a much more efficient way to do things. Let’s say I want to scan my computer for JPEGs and move them all to one folder:

~/$ find . -type f -name '*.jpeg' -exec mv -t myfolder {} +

Good luck doing that with Finder or Windows Explorer!

(A tip for understanding more complex commands like the one above: you can have them analysed by a tool like explainshell.com!)

Consistency

Apart from being efficient, the command line is also very consistent. GUIs come and go, their interfaces change, but terminals and shell commands stay the same. This means that I can execute the same commands and shell code I know from my laptops (Linux Mint and Ubuntu), in the shell of my Raspberry Pi, which I use as a home server, or in the shell of my company’s development and production servers, which run RHEL.

Necessity

When it comes to servers, it is clear that using GUIs is just not an option. No one in my team even has physical access to our company’s servers! And besides, there is no regular display or other I/O hooked up to them. All server access goes through a cryptographic network protocol called SSH, which is short for … “Secure Shell”.

Moreover, whenever you need to start a process, execute a script or an executable from within a programming language, this is also impossible without the shell. In Python, for instance, one way to do this is with os.system() or with os.popen() which returns stdout, like this:

import os
result = os.popen('ls -la').read()
print(result)

Text

One final advantage of using the shell is the fact that it is a text interface. At first this might seem as a drawback to GUIs, but it is actually an incredible benefit. Text commands can be saved, which makes them shareable and reproducible. Imagine a friend coming to you for help saying “I did something in Finder and now my Documents folder is gone!”, compared to him being able to enter history into the terminal and give you a complete list of all commands leading up to the problem…

Conclusion

Being familiar with shell commands and using a terminal emulator are indispensable skills for any software developer. They offer quick and dependable access to highly complex commands that are difficult or even impossible to execute using graphical applications.

More information

You can read more about this subject in the amazing GitHub repo: The Art of the Command Line

Hi! 👋 I’m Tom. I’m a software engineer, a technical writer and IT burnout coach. If you want to get in touch, check out https://tomdeneire.github.io

Programming
Shell
Terminal
Unix
Learning To Code
Recommended from ReadMedium