<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Thibaut Rousseau</title>
    <description>The latest articles on Forem by Thibaut Rousseau (@thiht).</description>
    <link>https://forem.com/thiht</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F10484%2F2n3lcUGe.jpeg</url>
      <title>Forem: Thibaut Rousseau</title>
      <link>https://forem.com/thiht</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/thiht"/>
    <language>en</language>
    <item>
      <title>TDD is a personal practice</title>
      <dc:creator>Thibaut Rousseau</dc:creator>
      <pubDate>Mon, 18 Dec 2023 16:12:19 +0000</pubDate>
      <link>https://forem.com/thiht/tdd-is-a-personal-practice-3o76</link>
      <guid>https://forem.com/thiht/tdd-is-a-personal-practice-3o76</guid>
      <description>&lt;p&gt;I know TDD. I know what real TDD is. I know how to do it right, whatever that means depending on the TDD practitioner.&lt;br&gt;
I still don’t like this practice, and rarely use it, except in 2 situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I’m fixing a bug in an existing code base: in this case I’ll write a test first to reproduce and isolate the bug, and then fix it and refactor if needed&lt;/li&gt;
&lt;li&gt;I’m adding a new use case to an existing feature, and will treat the lack of existence of this new case as a bug, see 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don’t ever, ever, EVER use TDD to write new features from scratch. It doesn’t work for me. It doesn’t match my mental model. It doesn’t help me go faster, doesn’t make me produce better code, and doesn’t make me write more, or more useful tests. I don't enjoy it and it doesn't provide me with any kind of satisfaction.&lt;/p&gt;

&lt;p&gt;I still have a personal methodology, but it’s not TDD. I still strive to write good test and maintain good coverage, but not doing TDD.&lt;/p&gt;

&lt;p&gt;TDD should not be forced upon developers who don’t want to follow it, in the same way a specific IDE should not be forced upon a developer. TDD is a tool, not a goal in itself. The shared goal is to have a well tested code base that is as safe as possible from regressions. How developers achieve that doesn’t matter.&lt;/p&gt;

&lt;p&gt;TDD should not be conflated as "writing tests". I often see the rhetoric that, if you don’t do TDD, then you don’t write tests. If I showed you a code base with tests, there would be no way for you to know if they’ve been written in TDD or not.&lt;/p&gt;

&lt;p&gt;TDD is not a team practice. Writing tests is a team practice. Code review is a team practice. Automated CI is a team practice. Whether a developer does or does not do TDD has no impact on the rest of the team. I could tell you I'm doing TDD if it pleases you, and you'd have no way to know that I don't, micro-managing set aside.&lt;/p&gt;

&lt;p&gt;If in TDD you trust, don’t proselytize it. TDD is a personal practice.&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>testing</category>
    </item>
    <item>
      <title>Shell aliases on steroids</title>
      <dc:creator>Thibaut Rousseau</dc:creator>
      <pubDate>Thu, 10 Feb 2022 20:31:56 +0000</pubDate>
      <link>https://forem.com/thiht/shell-aliases-on-steroids-4abg</link>
      <guid>https://forem.com/thiht/shell-aliases-on-steroids-4abg</guid>
      <description>&lt;p&gt;Aliases, whether you use Bash, ZSH or any other shell, are a really easy way to improve your day to day workflow. The basic syntax for aliases is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;l&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ls -al'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This syntax is pretty simple, but is unfortunately very limited in what you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it doesn't let you handle custom parameters. What if you want to add a custom &lt;code&gt;--json&lt;/code&gt; parameter to &lt;code&gt;curl&lt;/code&gt; that expands to &lt;code&gt;--header "Content-Type: application/json"&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;it doesn't let you add subcommands. What if you want to create a custom &lt;code&gt;docker sh&lt;/code&gt; subcommand that expands to &lt;code&gt;docker exec -it container_name sh&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well the cool thing is that you can do all of that, simply using shell functions! Yep, nothing new in here, but using functions to create advanced aliases is often disregarded or forgotten.&lt;/p&gt;

&lt;p&gt;Anyway, let's see how to implement the above aliases!&lt;/p&gt;

&lt;p&gt;Note: The following snippets will use Bash specifically. It should not be too hard to adapt them to other shells.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a custom flag to a command
&lt;/h2&gt;

&lt;p&gt;When using &lt;code&gt;curl&lt;/code&gt;, I often want to send JSON payloads. To do so, the &lt;code&gt;Content-Type: application/json&lt;/code&gt; header is usually required by servers. I'd like to be able to write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"foo": "bar"}'&lt;/span&gt; https://example.com/endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"foo": "bar"}'&lt;/span&gt; https://example.com/endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add this custom flag with the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; args&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;arg &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    case&lt;/span&gt; &lt;span class="nv"&gt;$arg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="nt"&gt;--json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; args+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"-H"&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; args+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;esac&lt;/span&gt;
  &lt;span class="k"&gt;done
  &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;curl &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what happens in this snippet?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At first, we create a new &lt;code&gt;curl&lt;/code&gt; function. It will wrap the already existing &lt;code&gt;curl&lt;/code&gt; command and we'll be able to modify how it's called.&lt;/li&gt;
&lt;li&gt;Then, we loop on all the arguments passed to the command, and add them to a new &lt;code&gt;args&lt;/code&gt; array.&lt;/li&gt;
&lt;li&gt;When we encounter the &lt;code&gt;--json&lt;/code&gt; argument, we push the new arguments &lt;code&gt;"-H" "Content-Type: application/json"&lt;/code&gt; to our list instead.&lt;/li&gt;
&lt;li&gt;Finally, we call the original &lt;code&gt;curl&lt;/code&gt; command with the modified list of arguments. Make sure to use &lt;code&gt;command&lt;/code&gt; in front of &lt;code&gt;curl&lt;/code&gt; to avoid calling the alias function recursively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! There's no magic in here, we just cleverly use some basic Bash building blocks.&lt;/p&gt;

&lt;p&gt;Using the same techniques, we can easily decide to replace the &lt;code&gt;-d&lt;/code&gt; argument with &lt;code&gt;--json&lt;/code&gt; to get the following final command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="s1"&gt;'{"foo": "bar"}'&lt;/span&gt; https://example.com/endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is left as an exercise to the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a custom subcommand to a command
&lt;/h2&gt;

&lt;p&gt;When using &lt;code&gt;docker&lt;/code&gt;, it's common to get into a container to explore the file hierarchy. The command to do this operation is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; container_name sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to write this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker sh container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The principle is the same as above, you can write a function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-ge&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    case&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="s2"&gt;"sh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-ne&lt;/span&gt; 2 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
          &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'"docker sh" requires 1 argument.'&lt;/span&gt;
          &lt;span class="nb"&gt;echo
          echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage:  docker sh NAME|ID"&lt;/span&gt;
          &lt;span class="nb"&gt;echo
          echo&lt;/span&gt; &lt;span class="s2"&gt;"Start an interactive shell inside a running container"&lt;/span&gt;
          &lt;span class="k"&gt;return &lt;/span&gt;1
        &lt;span class="k"&gt;fi
        &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash
        &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;esac&lt;/span&gt;
  &lt;span class="k"&gt;fi
  &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;docker &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only difference with the previous script is that we create a new &lt;code&gt;sh&lt;/code&gt; subcommand that we implement ourselves.&lt;br&gt;
We could trivially implement additional flags (&lt;code&gt;--help&lt;/code&gt;, &lt;code&gt;--bash&lt;/code&gt;, etc.) to our new subcommand following the same patterns.&lt;/p&gt;




&lt;p&gt;This article contains no novel concepts, but will helpfully help you get creative in creating more specific aliases to your workflows.&lt;/p&gt;

&lt;p&gt;The main thing to remember is the existence of the &lt;code&gt;command&lt;/code&gt; built-in that allows you to declare a function with the same name as an existing command, and still be able to use the original command.&lt;/p&gt;

</description>
      <category>shell</category>
      <category>bash</category>
    </item>
    <item>
      <title>Learn to use screen, a terminal multiplexer</title>
      <dc:creator>Thibaut Rousseau</dc:creator>
      <pubDate>Mon, 25 Sep 2017 20:04:23 +0000</pubDate>
      <link>https://forem.com/thiht/learn-to-use-screen-a-terminal-multiplexer-gl</link>
      <guid>https://forem.com/thiht/learn-to-use-screen-a-terminal-multiplexer-gl</guid>
      <description>&lt;p&gt;&lt;a href="https://www.gnu.org/software/screen/" rel="noopener noreferrer"&gt;screen&lt;/a&gt;, or GNU screen, is a terminal multiplexer. It allows to manage multiple terminal sessions within the same console. In a way, it does the same thing as modern terminal emulators such as &lt;a href="https://gnometerminator.blogspot.fr/p/introduction.html" rel="noopener noreferrer"&gt;Terminator&lt;/a&gt; or &lt;a href="https://www.enlightenment.org/about-terminology" rel="noopener noreferrer"&gt;Terminology&lt;/a&gt; with their built-in tab system and layout management. The main benefit is that screen also works through an SSH connection: you will be able to use your screen knowledge and configuration on any machine supporting screen in the world!&lt;/p&gt;

&lt;p&gt;screen has been around for almost 30 years so it's pretty stable now. It is released under the GPL license.&lt;/p&gt;

&lt;p&gt;The main issue I had when starting with screen was its relative difficulty when compared to simple terminal emulators. So &lt;strong&gt;I will make a tour of the most useful keyboard shortcuts for a practical use&lt;/strong&gt;, and share with you my screen config. You can also jump directly to the cheatsheet if you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;screen is not installed by default, so you need to install it first using your package manager.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;start screen&lt;/strong&gt;, open a terminal and run the command &lt;code&gt;screen&lt;/code&gt;. Not that hard, is it?&lt;/p&gt;

&lt;p&gt;We're ready to start learning screen. Don't worry, that's only a few commands!&lt;/p&gt;

&lt;h3&gt;
  
  
  Window managements
&lt;/h3&gt;

&lt;p&gt;Now you have opened screen, the first thing you need to know is how to &lt;strong&gt;create a new "window"&lt;/strong&gt; (i.e. a new virtual terminal). To do so, press the keys &lt;code&gt;Ctrl+a&lt;/code&gt;, and then press &lt;code&gt;c&lt;/code&gt;. The screen shortcuts all consist of &lt;code&gt;Ctrl+a&lt;/code&gt; (called "escape key" or "prefix") followed by another key. You now have two windows opened running in parallel, you can have vim in the first one, and a bash in the second one for example, and that's what screen is all about.&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;visualize all the opened windows&lt;/strong&gt; with &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;"&lt;/code&gt;. This view allows you to navigate through your windows with the arrow keys, the 0-9 numbers and the enter key. This command is great because it gives you a global overview of your current session, I used it a lot at first.&lt;/p&gt;

&lt;p&gt;But there are more ways to &lt;strong&gt;navigate through the windows&lt;/strong&gt;! I personally use almost exclusively the commands &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;p&lt;/code&gt; (&lt;strong&gt;p&lt;/strong&gt;revious window) and  &lt;code&gt;Ctrl + a&lt;/code&gt; &lt;code&gt;n&lt;/code&gt; (&lt;strong&gt;n&lt;/strong&gt;ext window). These shortcuts require to have your windows in mind though, but it comes with practice. And don't forget &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;"&lt;/code&gt; is here to rescue you in case of doubt. ;)&lt;/p&gt;

&lt;p&gt;It's also possible to jump to another window with the command &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;em&gt;&lt;code&gt;number&lt;/code&gt;&lt;/em&gt;, where &lt;em&gt;number&lt;/em&gt; is a number between 0 and 9. This matches the "Num" column of the &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;"&lt;/code&gt; view.&lt;/p&gt;

&lt;p&gt;Finally, you can &lt;strong&gt;kill a window&lt;/strong&gt; when you have no use for it anymore. To do so, just press &lt;code&gt;Ctrl+d&lt;/code&gt; in the shell. There's also a screen command with the "same" effect but it's usually better to proceed this way. Note if you kill all the windows of a session, the session terminates.&lt;/p&gt;




&lt;p&gt;Summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;c&lt;/code&gt; to create a new window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;"&lt;/code&gt; to visualize the opened windows&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;n&lt;/code&gt; to switch with the previous/next window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;em&gt;&lt;code&gt;number&lt;/code&gt;&lt;/em&gt; to switch to the window &lt;em&gt;number&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+d&lt;/code&gt; to kill a window&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Session management
&lt;/h3&gt;

&lt;p&gt;Now you can manage your windows, it is time you learn how to manage your screen sessions.&lt;/p&gt;

&lt;p&gt;You just learned you can terminate a session by killing all its windows, that's a good start. We will now see how to &lt;strong&gt;exit a session without killing it&lt;/strong&gt;. It means you'll be able to manage multiple persistent sessions in parallel. This is called "detaching" a session. To be clear, a &lt;strong&gt;detached session&lt;/strong&gt; is a session which is still active in background, but on which no one is connected. An &lt;strong&gt;attached session&lt;/strong&gt; is a session which is active and currently used.&lt;/p&gt;

&lt;p&gt;The first thing I'll ask you to do is to kill your current screen session if you haven't done it already. You can then &lt;strong&gt;list all your screen sessions&lt;/strong&gt; by running the command &lt;code&gt;screen -ls&lt;/code&gt;. If all your sessions are closed, it should print something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No Sockets found in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we'll start a &lt;strong&gt;new session&lt;/strong&gt;, but &lt;strong&gt;we'll give it a name&lt;/strong&gt; so that we can come back to it more easily later. Run the command &lt;code&gt;screen -S my_session&lt;/code&gt;. If you run the command &lt;code&gt;screen -ls&lt;/code&gt;, you should obtain something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There is a screen on:
    10321.my_session        (Attached)
1 Socket in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since you're connected to the session, it's presented as &lt;strong&gt;attached&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now you're connected to a session named "my_session", you can &lt;strong&gt;detach it from the current terminal&lt;/strong&gt; with the command &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;d&lt;/code&gt;. This should result in a message like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[detached from 10321.my_session]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As usual, you can list the currently running sessions with &lt;code&gt;screen -ls&lt;/code&gt;. This time, "my_session" should be listed as &lt;strong&gt;detached&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There is a screen on:
    10321.my_session        (Detached)
1 Socket in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I suggest you start and detach a few screen sessions to understand how it works. &lt;strong&gt;Be careful not to use the same session name twice&lt;/strong&gt;, screen allows it but it can be more painful to resume a session if there are name conflicts.&lt;/p&gt;

&lt;p&gt;With multiple screen sessions, the &lt;code&gt;screen -ls&lt;/code&gt; gives something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There are screens on:
    10474.downloads (Detached)
    10427.work      (Detached)
    10321.my_session        (Detached)
3 Sockets in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If there aren't any conflicts, you can &lt;strong&gt;resume a session&lt;/strong&gt; simply with the command &lt;code&gt;screen -x session_name&lt;/code&gt;. So for example if you run &lt;code&gt;screen -x my_session&lt;/code&gt;, your session "my_session" will be resumed with the windows you opened before! And if you run &lt;code&gt;screen -ls&lt;/code&gt;, it should appear as &lt;strong&gt;attached&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There are screens on:
    10474.downloads (Detached)
    10427.work      (Detached)
    10321.my_session        (Attached)
3 Sockets in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A last useful thing you should know is how to &lt;strong&gt;kill a detached session without connecting to it&lt;/strong&gt;. To do so, the command to run is a bit tricky: &lt;code&gt;screen -S session_name -X quit&lt;/code&gt;. This means you pass the command "quit" to the session named "session_name". It's a bit hard to remember so I generally simply resume my session and kill all its windows one by one.&lt;/p&gt;




&lt;p&gt;Summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;screen -ls&lt;/code&gt; to list the sessions and their status&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screen -S session_name&lt;/code&gt; to start a session with a given name. The name
should be unique&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;d&lt;/code&gt; to detach a session&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screen -x session_name&lt;/code&gt; to resume (reattach) a session knowing its name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screen -S session_name -X quit&lt;/code&gt; to terminate a detached session&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced usage
&lt;/h2&gt;

&lt;p&gt;The hardest part is over! You have discovered screen and you know how to use it. All you need now is practice.&lt;/p&gt;

&lt;p&gt;In this section, I'll present a few interesting features of screen, but they're definitely not necessary to use it, so feel free to come back and read this part later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout management
&lt;/h3&gt;

&lt;p&gt;In the introduction, I talked about how Terminator and Terminology can work as layout managers. The good news is screen also permits to do that. So to &lt;strong&gt;split horizontally&lt;/strong&gt;, you can use the command &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;S&lt;/code&gt;, and to &lt;strong&gt;split vertically&lt;/strong&gt; you can use &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;|&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;switch to the next region&lt;/strong&gt; (this is how the split panes are called), the command to use is &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;/code&gt;. Each region behaves normally: you can run any command you have learned so far.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;close the current region&lt;/strong&gt;, use &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;X&lt;/code&gt;. If you work with a lot of panes, you can &lt;strong&gt;close them all but the current one&lt;/strong&gt; with &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;Q&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;S&lt;/code&gt; to split horizontally&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; to split vertically&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;/code&gt; to switch to the next region&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;X&lt;/code&gt; to close the current region&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;Q&lt;/code&gt; to close all the regions but the current one&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Work with the buffer
&lt;/h3&gt;

&lt;p&gt;To follow, I'll talk about an important feature of screen: the copy mode, or scrollback mode.&lt;/p&gt;

&lt;p&gt;To &lt;strong&gt;enter the copy mode&lt;/strong&gt;, the command is either &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; or &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;[&lt;/code&gt;, choose your side. The copy mode allows you to &lt;strong&gt;navigate through the console buffer without using your mouse&lt;/strong&gt;. Since you can't use your wheel to scroll by default, this is the normal way to go back in the results. This mode lets you use some vim commands for the movements (arrow keys, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;g&lt;/code&gt;, &lt;code&gt;G&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;copy some text&lt;/strong&gt; (that's what the mode is for!) by marking the beginning and the end of a section with the space bar. You can then &lt;strong&gt;paste it&lt;/strong&gt; with &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;]&lt;/code&gt;.  For more informations, check the &lt;code&gt;man screen&lt;/code&gt; and look for "copy".&lt;/p&gt;




&lt;p&gt;Summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; or &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;[&lt;/code&gt; to enter in copy mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Space&amp;gt;&lt;/code&gt; to select and copy some text in copy mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;]&lt;/code&gt; to paste the content of the buffer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Session sharing
&lt;/h3&gt;

&lt;p&gt;I'll finish with a last screen feature I want you to know about: it allows to share a session between multiple users. When working on a remote server, this comes really handy.&lt;/p&gt;

&lt;p&gt;So first, you have to start a session as usual. Then, we'll use the command mode of screen to enable the multiuser mode and give the access right to some users. To &lt;strong&gt;enter the command mode&lt;/strong&gt;, type &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt;. You can then &lt;strong&gt;enable the multiuser mode&lt;/strong&gt; with the command &lt;strong&gt;multiuser on&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then to &lt;strong&gt;add a specific user to the session&lt;/strong&gt;, enter the command mode again with &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; and type the command &lt;strong&gt;acladd &lt;em&gt;username&lt;/em&gt;&lt;/strong&gt; (ACL stands for "Access Control List") with the name of the user you want to add instead of &lt;em&gt;username&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The user &lt;em&gt;username&lt;/em&gt; is now able to &lt;strong&gt;join your session&lt;/strong&gt; simply with the command &lt;code&gt;screen -x your_username/session_name&lt;/code&gt;. The session is completely shared, which means you can see what the other users do in real time and so can they.&lt;/p&gt;

&lt;p&gt;When a session is shared with multiple users, it can be nice to &lt;strong&gt;know who is currently connected on it&lt;/strong&gt;. You can have this info and more thanks to the command &lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;*&lt;/code&gt;. The view shows a few useful informations, namely the window a user is currently using, or their permissions.&lt;/p&gt;

&lt;p&gt;Finally, you can &lt;strong&gt;revoke the access rights of user&lt;/strong&gt; with the command &lt;strong&gt;acldel &lt;em&gt;username&lt;/em&gt;&lt;/strong&gt; in command mode. There's more you can do to manage a shared session, but I won't go into details, the man page covers everything. Now you have a basic understanding of screen, it should be easier to understand.&lt;/p&gt;




&lt;p&gt;Summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; to switch to command mode&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"multiuser on" to enable the multiuser mode&lt;/li&gt;
&lt;li&gt;"acladd &lt;em&gt;username&lt;/em&gt;" to give the access rights to the user &lt;em&gt;username&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;"acldel &lt;em&gt;username&lt;/em&gt;" to remove the access rights to the user &lt;em&gt;username&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;screen -x owner/session_name&lt;/code&gt; to join a session started by another user&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; to list the other connections to a session&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Automatically list the screen sessions
&lt;/h3&gt;

&lt;p&gt;When I start my terminal, I like it to list the current screen sessions. To do so, I simply added the &lt;code&gt;screen -ls&lt;/code&gt; command to my .bashrc. So now whenever I open a terminal, I'm welcomed with my screen status:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There are screens on:
    2927.my_screen3 (Attached)
    2882.my_screen2 (Attached)
    2840.my_screen1 (Detached)
3 Sockets in /var/run/screen/S-thiht.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Not only is it really useful to have this status without asking for it, but it is also a good way to think about always using screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good aliases
&lt;/h3&gt;

&lt;p&gt;As you're now aware, screen uses a lot of options. I tried to keep only the most useful in this article but they're still a pain to remember. A good way to remember them is to use aliases. I personally use the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'screen -S'&lt;/span&gt;  &lt;span class="c"&gt;# sn for screen new&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'screen -ls'&lt;/span&gt; &lt;span class="c"&gt;# sl for screen list&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;sr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'screen -x'&lt;/span&gt;  &lt;span class="c"&gt;# sr for screen resume&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;sk&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# sk for screen kill&lt;/span&gt;
  &lt;span class="c"&gt;# function instead of alias because the order of the parameters matters&lt;/span&gt;
  screen &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; quit
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These aliases don't conflict with anything standard and they're really easier to remember and to type, so I strongly advise you to use them!&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom configuration
&lt;/h3&gt;

&lt;p&gt;screen can be customized in various ways through a .screenrc file, located in your home folder. One of the most useful tricks is the status bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dj0im6helajfmunn1yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dj0im6helajfmunn1yk.png" alt="screen session with a status bar" width="787" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I won't go through the configuration of screen in details (you can read &lt;code&gt;man screen&lt;/code&gt; or other articles to learn more), but simply share my commented .screenrc with you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# enable the altscreen
# for example in vim, it allows to scroll with the mouse without
# "overflowing" on the terminal
# also it doesn't "pollute" the terminal when you quit vim
altscreen on

# automatically detach the session if the terminal is closed
autodetach on

# larger command history
defscrollback 10000

# set the encoding of the windows to utf-8
defutf8 on

# disable the startup message
startup_message off

# allow to scroll
termcapinfo xterm* ti@:te@

# disable the annoying visual bell
vbell off

# status bar
# %{= wk}: set the color to white on black
# %S: screen session name
# %-w: previous windows
# %{= kw}: set the color to black on white
# %n: current window number
# %t: current window title
# %{= wk}: set the color to white on black
# %+w: next windows
caption always "%{= wk}%S: %-w%{= kw}%n %t%{= wk}%+w"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note you can enable any of these options directly from screen's command mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cheatsheet of the main commands
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Basic usage
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start a session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen -ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;List&lt;/strong&gt; the sessions and their status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen -S session_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;S&lt;/strong&gt;tart a session named "session_name"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen -x session_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resume the session named "session_name"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen -S session_name -X quit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Terminate the session named "session_name"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;c&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;C&lt;/strong&gt;reate a new window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;k&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;K&lt;/strong&gt;ill the current window (&lt;a href="https://en.wikipedia.org/wiki/End-of-transmission_character" rel="noopener noreferrer"&gt;&lt;code&gt;Ctrl+d&lt;/code&gt;&lt;/a&gt; does the same thing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;List the opened windows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;p&lt;/code&gt;/&lt;code&gt;n&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Go to the &lt;strong&gt;p&lt;/strong&gt;revious/&lt;strong&gt;n&lt;/strong&gt;ext window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;0&lt;/code&gt;-&lt;code&gt;9&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Go to the window &lt;em&gt;n&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;d&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;D&lt;/strong&gt;etach the screen session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Enter the command mode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Split mode
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;S&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;S&lt;/strong&gt;plit horizontally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;â˜&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Split vertically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Go to the next region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;X&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Close the current region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;Q&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Close all the regions but the current one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Copy mode
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;/&lt;code&gt;[&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Enter the copy mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Space&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark a selection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Paste the content of the buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Shared session
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;multiuser on&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Enable the multiuser mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;acladd username&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Give the access rights to &lt;em&gt;username&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;acldel username&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Revoke the access rights to &lt;em&gt;username&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+a&lt;/code&gt; &lt;code&gt;*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;List the other connections to the session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;screen -x owner/session_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Join a session started by another user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;screen is a powerful tool if you use the terminal a lot. Yet, it has some drawbacks, that can be pretty annoying. To list a few you &lt;strong&gt;will&lt;/strong&gt; be confronted to if you really try to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bad UTF-8 support. There are a few configurations to make screen work fine with unicode, but it's still a bit messy. I am not even sure there is a proper way to handle UTF-8 characters in the status bar...&lt;/li&gt;
&lt;li&gt;insane status bar configuration. You can see it in the .screenrc I provided, crafting a neat status bar is really hard. It's a shame given how useful they are!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good news though, all these issues are allegedly solved with &lt;a href="https://tmux.github.io/" rel="noopener noreferrer"&gt;tmux&lt;/a&gt;, another more recent terminal mutiplexer. I've only used it as a replacement of screen for a few days so I will wait a bit before reviewing it, but it's very similar to screen in its usage, and I'm very satisfied with it so far.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>shell</category>
      <category>bash</category>
      <category>screen</category>
    </item>
    <item>
      <title>Shell Scripts Matter</title>
      <dc:creator>Thibaut Rousseau</dc:creator>
      <pubDate>Sun, 12 Mar 2017 22:57:11 +0000</pubDate>
      <link>https://forem.com/thiht/shell-scripts-matter</link>
      <guid>https://forem.com/thiht/shell-scripts-matter</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4bbcxmfn4d2xkqggzns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4bbcxmfn4d2xkqggzns.png" alt="Bash Logo" width="128" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The shell is an odd beast. Although it goes against every current trend in software engineering (strong typing, compile checks over runtime checks, ...), shell scripts are here to stay, and still constitute an important part of every developer's life.&lt;/p&gt;

&lt;p&gt;The weird thing about shell scripts is that even strong advocates of good practices gladly forget all they know when it comes to shell scripting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Versioning? Why bother, it's disposable code.&lt;/p&gt;

&lt;p&gt;Code quality? That's just a shell script, it's garbage anyway.&lt;/p&gt;

&lt;p&gt;Testing? Nah. There aren't any decent tools for that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wrong, wrong, and wrong. Shell scripts have value. &lt;strong&gt;Everything you do for real code should be done for non trivial shell scripts&lt;/strong&gt;, even for a one-time script. That includes versioning, code reviews, continuous integration, static code analysis, and testing.&lt;/p&gt;

&lt;p&gt;Here is a summary of everything that can, and should be done when writing shell scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article will use Bash as a reference shell. Most of the content can be transposed to other POSIX compliant shells.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your scripts in version control
&lt;/h2&gt;

&lt;p&gt;Keeping shell scripts under version control has multiple advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It constitutes a library. Shell scripts can be hard to write. If there's a reference for something difficult somewhere, your coworkers will thank you when they need it. &lt;strong&gt;You should setup a "shell-scripts" repository&lt;/strong&gt; somewhere as soon as possible.&lt;/li&gt;
&lt;li&gt;They can be properly reviewed. Making mistakes is easy with shell scripts, and they can be very damaging. &lt;strong&gt;Code review should be mandatory for shell scripts&lt;/strong&gt;, as for any other piece of code.&lt;/li&gt;
&lt;li&gt;They can be improved. I won't explain to you what version control is. But with shell scripts versioned, it's easy to improve them regularly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please, from now on, &lt;strong&gt;version all your shell scripts&lt;/strong&gt; before running them. &lt;strong&gt;Have someone reviewing your scripts in priority&lt;/strong&gt; before executing them in production. It's not a waste of your coworkers' time, it's a time saver for the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve the quality of your scripts with ShellCheck
&lt;/h2&gt;

&lt;p&gt;Although you can check the syntactic validity of your scripts with the command &lt;code&gt;bash -n&lt;/code&gt;, much powerful tools exist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.shellcheck.net/" rel="noopener noreferrer"&gt;ShellCheck&lt;/a&gt; is a static code analysis tool for shell scripts. It's really an awesome tool which will help you improve your skills as you use it. &lt;strong&gt;So do use it&lt;/strong&gt;. You can &lt;a href="https://github.com/koalaman/shellcheck#installing" rel="noopener noreferrer"&gt;install it globally on your machine&lt;/a&gt;, use it in your &lt;a href="https://github.com/koalaman/shellcheck#travis-ci-setup" rel="noopener noreferrer"&gt;continuous integration&lt;/a&gt;, and it even &lt;a href="https://github.com/koalaman/shellcheck#in-your-editor" rel="noopener noreferrer"&gt;integrates perfectly with most major editors&lt;/a&gt;. There really are no downsides to using ShellCheck and it can save you from yourself.&lt;/p&gt;

&lt;p&gt;If Steam had used ShellCheck in 2015, &lt;a href="https://linux.slashdot.org/story/15/01/16/1429201/steam-for-linux-bug-wipes-out-all-of-a-users-files" rel="noopener noreferrer"&gt;this line would never have made it to production&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STEAMROOT&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code violates the &lt;a href="https://github.com/koalaman/shellcheck/wiki/SC2115" rel="noopener noreferrer"&gt;SC2115 rule&lt;/a&gt; from ShellCheck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Bash unofficial strict mode
&lt;/h2&gt;

&lt;p&gt;The unofficial strict mode comes from Aaron Maxwell's article "&lt;a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/" rel="noopener noreferrer"&gt;Use the Unofficial Bash Strict Mode (Unless You Looove Debugging)&lt;/a&gt;". He suggests to start every Bash script with the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;set -e&lt;/code&gt; will exit the script if any command returns a non-zero status code. To prevent the option from triggering on commands returning a non-zero status code even when no error occurred, there are two solutions:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;using the &lt;code&gt;|| true&lt;/code&gt; pattern:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;command_returning_non_zero &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;temporary disabling the option:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +e
command_returning_non_zero
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;set -u&lt;/code&gt; will prevent using an undefined variable. In the case of undefined positional parameters (&lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, ...), you can give them a default value with the &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html" rel="noopener noreferrer"&gt;parameter expansion&lt;/a&gt; construct:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;my_arg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;set -o pipefail&lt;/code&gt; will force pipelines to fail on the first non-zero status code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;IFS=$'\n\t'&lt;/code&gt; makes iterations and splitting less surprising, in the case of loops mostly. The default for this variable is usually &lt;code&gt;IFS=$' \n\t'&lt;/code&gt; but the space as a separator often gives confusing results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read the &lt;a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/" rel="noopener noreferrer"&gt;original article&lt;/a&gt; for more details and &lt;a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/#issues-and-solutions" rel="noopener noreferrer"&gt;solutions for common challenges when using the strict mode&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The unofficial strict mode is more intrusive than what we've seen before and can be hard to deal with, but it's worth it in the long run. Take the time to try it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do some cleanup!
&lt;/h2&gt;

&lt;p&gt;When scripts are interrupted, either because of a user's action or because something bad occurred, most shell scripts don't clean up their mess. In the worst case, they might not restart services they had to temporarily disable. It's a shame given how easy it is to perform some cleanup and error catching with the &lt;code&gt;trap&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Once again, in "&lt;a href="http://redsymbol.net/articles/bash-exit-traps/" rel="noopener noreferrer"&gt;How "Exit Traps" Can Make Your Bash Scripts Way More Robust And Reliable&lt;/a&gt;", Aaron Maxwell gives some great advice.&lt;/p&gt;

&lt;p&gt;Always add the following in your shell scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cleanup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;trap&lt;/code&gt; command will execute the &lt;code&gt;cleanup&lt;/code&gt; function as soon as the script exits. In this function you could remove temporary files, restart services, or whatever is relevant to your script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test your scripts with shUnit2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/kward/shunit2" rel="noopener noreferrer"&gt;shUnit2&lt;/a&gt; is a unit testing framework for shell scripts. It's inspired by JUnit. It's available in the standard repositories so you can install it with &lt;code&gt;apt-get install shunit2&lt;/code&gt; on an Ubuntu-based distro.&lt;/p&gt;

&lt;p&gt;shUnit2 consists of a shell script you can &lt;code&gt;source&lt;/code&gt; in your test file. To use it, there are multiple approaches. In order not to clutter the main script, I prefer writing the tests in a separate file. This means I'll have a &lt;code&gt;script.sh&lt;/code&gt; file and a &lt;code&gt;test_script.sh&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Below is an example for a script offering a function to add two numbers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;add.sh&lt;/code&gt; must have the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;add&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt; a &lt;span class="o"&gt;+&lt;/span&gt; b &lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Main code of the script&lt;/span&gt;
    add &lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;[[ "${BASH_SOURCE[0]}" = "$0" ]]&lt;/code&gt; test is used to execute the main code only when the script is executed directly, not &lt;code&gt;source&lt;/code&gt;d.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;test_add.sh&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ./add.sh

test_add&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;add 5 8&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;13
    assertEquals &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$actual&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; shunit2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, the test file &lt;code&gt;source&lt;/code&gt;s the main file &lt;code&gt;add.sh&lt;/code&gt; (in Bash, &lt;code&gt;.&lt;/code&gt; is an alias to &lt;code&gt;source&lt;/code&gt;). The functions it declares are then available in the test script.&lt;/p&gt;

&lt;p&gt;The actual tests are simple functions with a name starting by &lt;code&gt;test&lt;/code&gt;. At the end, the globally installed &lt;code&gt;shunit2&lt;/code&gt; is &lt;code&gt;source&lt;/code&gt;d and performs its &lt;a href="http://ssb.stsci.edu/testing/shunit2/shunit2.html#quickstart" rel="noopener noreferrer"&gt;magic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The test file can then be executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bash test_add.sh
test_add

Ran 1 test.

OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The details of what shUnit2 can do are explained in &lt;a href="http://ssb.stsci.edu/testing/shunit2/shunit2.html#function-reference" rel="noopener noreferrer"&gt;its documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are alternatives to shUnit2, such as &lt;a href="https://github.com/sstephenson/bats" rel="noopener noreferrer"&gt;Bats&lt;/a&gt; or &lt;a href="https://bmizerany.github.io/roundup/" rel="noopener noreferrer"&gt;Roundup&lt;/a&gt; but I didn't have a chance to use them yet. Their usage should be relatively similar though. The point of this section is that &lt;strong&gt;testing shell scripts is doable and should be done&lt;/strong&gt;, whatever solution you choose in the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log what your script is doing
&lt;/h2&gt;

&lt;p&gt;In the past, I made the mistake of not logging anything. I liked running a script and seeing it work magically without anything ugly showing in the console. I was wrong, because when something doesn't work as expected, it becomes impossible to know what happened. Running a script is not supposed to feel like magic, it must be somewhat verbose and understandable. For that, please &lt;strong&gt;log as much as possible in your scripts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For this purpose, I usually add the following lines in my scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;readonly &lt;/span&gt;&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
info&lt;span class="o"&gt;()&lt;/span&gt;    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[INFO]    &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
warning&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[WARNING] &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
error&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[ERROR]   &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
fatal&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[FATAL]   &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tiny logging framework allows to easily keep track of whatever happens during the script execution. Logging becomes as simple as writing &lt;code&gt;info "Executing this and that..."&lt;/code&gt;. Then it's easy to &lt;code&gt;grep&lt;/code&gt; on the log file to find something specific. Feel free to improve these functions as you need, with the date, the calling function name (with &lt;code&gt;$FUNCNAME&lt;/code&gt;), etc.&lt;/p&gt;

&lt;p&gt;I don't use the builtin &lt;a href="http://man7.org/linux/man-pages/man1/logger.1.html" rel="noopener noreferrer"&gt;&lt;code&gt;logger&lt;/code&gt;&lt;/a&gt; because it requires special privileges to write to &lt;code&gt;/var/log&lt;/code&gt; and I'm not fond of its usage. Writing to a log file in &lt;code&gt;/tmp&lt;/code&gt; is usually good enough. For &lt;code&gt;cron&lt;/code&gt; scripts though you should probably investigate &lt;code&gt;logger&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;-v&lt;/code&gt; or &lt;code&gt;--verbose&lt;/code&gt; of the commands you invoke as needed to improve the quality of your logging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn to debug your scripts
&lt;/h2&gt;

&lt;p&gt;The easiest way to debug a shell script, besides logging, is to run it with &lt;code&gt;bash -x&lt;/code&gt;. Another way is to use &lt;code&gt;set -x&lt;/code&gt; inside the script. This option will make Bash print every command before its execution, replacing the variables with their real values. Used together with the unofficial strict mode, this method is useful to see what's going on in a script with less risk to break the environment.&lt;/p&gt;

&lt;p&gt;It's also worth knowing that a few debuggers for Bash exist, for example &lt;a href="http://bashdb.sourceforge.net/bashdb.html" rel="noopener noreferrer"&gt;bashdb&lt;/a&gt;. bashdb works in the same way as gdb, and can be used to add breakpoints, switching to step by step execution, showing the value of variables, etc. You can learn how to use bashdb with the video "&lt;a href="https://www.youtube.com/watch?v=jbOQJDSTksA" rel="noopener noreferrer"&gt;Using BashDB to Debug Your Shell Scripts &lt;/a&gt;": &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/jbOQJDSTksA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Document your scripts
&lt;/h2&gt;

&lt;p&gt;Any shell script should have a &lt;code&gt;--help&lt;/code&gt; option. This doesn't seem easy? It is, thanks to the following wizardry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#/ Usage: add &amp;lt;first number&amp;gt; &amp;lt;second number&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#/ Compute the sum of two numbers&lt;/span&gt;
usage&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'^#/'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-c4-&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; : &lt;span class="s2"&gt;".*--help"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; usage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;usage&lt;/code&gt; function will print every line starting with &lt;code&gt;#/&lt;/code&gt; comments, without this prefix.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;expr&lt;/code&gt; command will check if the string resulting of the concatenation of all the parameters contains &lt;code&gt;--help&lt;/code&gt;. If so, it will call &lt;code&gt;usage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is definitely not the cleanest way to parse parameters, but this quick method ensures you will add a &lt;code&gt;--help&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;For the sake of good practices, &lt;a href="https://stackoverflow.com/a/14203146/1544176" rel="noopener noreferrer"&gt;this StackOverflow post&lt;/a&gt; explains how to properly parse a script's parameters using the &lt;code&gt;while&lt;/code&gt;/&lt;code&gt;case&lt;/code&gt;/&lt;code&gt;shift&lt;/code&gt; construct.&lt;/p&gt;

&lt;p&gt;To generate HTML documentation from your comments, you can also check &lt;a href="http://rtomayko.github.io/shocco/" rel="noopener noreferrer"&gt;shocco.sh&lt;/a&gt;, which inspired &lt;a href="https://github.com/rtomayko/shocco/blob/e4660e563559d5bd9acbca42b61115e72b54667f/shocco.sh#L54-L57" rel="noopener noreferrer"&gt;the above trick&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Random advice
&lt;/h2&gt;

&lt;p&gt;The following is a list of random good practices I've learned the hard way. I'll explain the rationale behind every advice as I go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Bash for scripting
&lt;/h3&gt;

&lt;p&gt;Use Bash by default, Sh if you have to. Try to forget about Ksh, Zsh or Fish unless there are really good reasons to use them. This choice not only ensures your script will work virtually everywhere, but also fosters comprehension of a script by the whole team. You don't write production scripts for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Bashisms
&lt;/h3&gt;

&lt;p&gt;If you use Bash, don't half-use it. Use &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html" rel="noopener noreferrer"&gt;parameter expansion&lt;/a&gt;. Use &lt;a href="http://tldp.org/LDP/abs/html/localvar.html" rel="noopener noreferrer"&gt;local&lt;/a&gt; and &lt;a href="https://ss64.com/bash/readonly.html" rel="noopener noreferrer"&gt;readonly&lt;/a&gt; variables. Use &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html" rel="noopener noreferrer"&gt;improved conditional expressions&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quote your variables
&lt;/h3&gt;

&lt;p&gt;Even if you know quoting is not required, it's a good habit to always quote variables. The only exception is when you specifically want expansion to occur. More on &lt;a href="https://github.com/koalaman/shellcheck/wiki/SC2086" rel="noopener noreferrer"&gt;word splitting&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Name your parameters
&lt;/h3&gt;

&lt;p&gt;This goes without saying, but explicitly naming parameters (&lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, ...) makes the code self-documenting and helps readability. The parameter expansion of Bash is a great candidate for naming and assigning default values to positional parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;my_arg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use subshells as a way to control what's in your global scope
&lt;/h3&gt;

&lt;p&gt;An example is worth a thousand words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt;
    &lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will print:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
1
5
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My main usage for this is when I need to temporarily modify &lt;code&gt;$IFS&lt;/code&gt; (for iterating over simple CSV-like files for example) and reset it to its original value afterwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use a template
&lt;/h3&gt;

&lt;p&gt;This script template summarizes every snippets shared along this article. I believe it's a good basis for any kind of script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;

&lt;span class="c"&gt;#/ Usage:&lt;/span&gt;
&lt;span class="c"&gt;#/ Description:&lt;/span&gt;
&lt;span class="c"&gt;#/ Examples:&lt;/span&gt;
&lt;span class="c"&gt;#/ Options:&lt;/span&gt;
&lt;span class="c"&gt;#/   --help: Display this help message&lt;/span&gt;
usage&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'^#/'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-c4-&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; : &lt;span class="s2"&gt;".*--help"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; usage

&lt;span class="nb"&gt;readonly &lt;/span&gt;&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;
info&lt;span class="o"&gt;()&lt;/span&gt;    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[INFO]    &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
warning&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[WARNING] &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
error&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[ERROR]   &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
fatal&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[FATAL]   &lt;/span&gt;&lt;span class="nv"&gt;$*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1 &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

cleanup&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# Remove temporary files&lt;/span&gt;
    &lt;span class="c"&gt;# Restart services&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
    &lt;span class="c"&gt;# Script goes here&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stay informed
&lt;/h3&gt;

&lt;p&gt;Shell scripting isn't moving that much these days. It's a great reason to read stuff about the topic, it makes it easy to keep up! Here are some interesting resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;man bash&lt;/code&gt;, I bet almost none of you have read it, yet it's a great source of information! And it's not that hard to read, I promise.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/UnixToolTip" rel="noopener noreferrer"&gt;@UnixTooltip&lt;/a&gt; on Twitter, continuously gives tips and tricks.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/tagged/bash?sort=votes&amp;amp;pageSize=15" rel="noopener noreferrer"&gt;Most upvoted Bash questions on StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/documentation/bash/topics" rel="noopener noreferrer"&gt;Bash participative documentation on StackOverflow&lt;/a&gt; has some interesting examples.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/koalaman/shellcheck/wiki" rel="noopener noreferrer"&gt;ShellCheck's wiki&lt;/a&gt; is a good resource to learn what not to do, and why.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://news.ycombinator.com/news" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/programming/" rel="noopener noreferrer"&gt;/r/programming&lt;/a&gt;, once in a while articles on this subject pop out.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I hope this article brought light on what was possible with shell scripting. The tools are there. You know the practices. Now it's up to you to make scripting a delight to work with, for you and your team!&lt;/p&gt;

</description>
      <category>shell</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
