<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Bash on dwmkerr.com</title><link>https://dwmkerr.com/categories/bash/</link><description>Recent content in Bash on dwmkerr.com</description><generator>Hugo -- gohugo.io</generator><language>en-uk</language><managingEditor>Dave Kerr</managingEditor><copyright>Copright &amp;copy; Dave Kerr</copyright><lastBuildDate>Sun, 25 Sep 2022 00:00:00 +0000</lastBuildDate><atom:link href="https://dwmkerr.com/categories/bash/index.xml" rel="self" type="application/rss+xml"/><item><title>A simple Makefile 'help' command</title><link>https://dwmkerr.com/makefile-help-command/</link><pubDate>Sun, 25 Sep 2022 00:00:00 +0000</pubDate><guid>https://dwmkerr.com/makefile-help-command/</guid><description>&lt;p&gt;In this article I&amp;rsquo;m going to show you how to add a &lt;code&gt;make help&lt;/code&gt; command to your makefiles that quickly and easily shows simple documentation for your commands:&lt;/p&gt;
&lt;p&gt;&lt;img src="./images/demo.svg" alt="Screen recording of the &amp;lsquo;makefile help&amp;rsquo; command in action"&gt;&lt;/p&gt;
&lt;p&gt;To add the &lt;code&gt;help&lt;/code&gt; command to your makefile, add a recipe like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-make" data-lang="make"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;help&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Show help for each of the Makefile recipes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;^[a-zA-Z0-9 -]+:.*#&amp;#39;&lt;/span&gt; Makefile | sort | &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; read -r l; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 1 -d&amp;#39;:&amp;#39;)\033[00m:&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 2- -d&amp;#39;#&amp;#39;)\n&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now just make sure that each of your recipes has a comment that follows the recipe name, which will be used as its documentation. For example, my &lt;a href="https://github.com/dwmkerr/dwmkerr.com"&gt;website repository&lt;/a&gt; has the following recipes in the makefile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-make" data-lang="make"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;default&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;help&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Show help for each of the Makefile recipes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @grep -E &lt;span style="color:#e6db74"&gt;&amp;#39;^[a-zA-Z0-9 -]+:.*#&amp;#39;&lt;/span&gt; Makefile | sort | &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; read -r l; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 1 -d&amp;#39;:&amp;#39;)\033[00m:&lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;(echo &lt;/span&gt;$$&lt;span style="color:#e6db74"&gt;l | cut -f 2- -d&amp;#39;#&amp;#39;)\n&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; setup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setup&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Setup tools required for local development.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; brew install hugo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hugo version
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git submodule update --init --recursive --remote
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; newpost
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;newpost&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Create a new post.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo new posts/my-first-post.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; serve
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serve&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Serve the site locally for testing.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo server --baseURL &lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost/&amp;#34;&lt;/span&gt; --buildDrafts -v --debug
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;.PHONY&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; build &lt;span style="color:#75715e"&gt;# Build the site.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;build&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cd dwmkerr.com; hugo --minify
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this setup, you can just enter &lt;code&gt;make&lt;/code&gt;, or &lt;code&gt;make help&lt;/code&gt;, to see the output below:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ make help
help: Show help for each of the Makefile recipes.
newpost: Create a new post.
serve: Serve the site locally for testing.
setup: Setup tools required for local development.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Simple! You can find the code at:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/makefile-help"&gt;https://github.com/dwmkerr/makefile-help&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it Works&lt;/h2&gt;
&lt;p&gt;This project was inspired by the project &lt;a href="https://github.com/FalcoSuessgott/golang-cli-template"&gt;&lt;code&gt;golang-cli-template&lt;/code&gt;&lt;/a&gt;, which I noticed had this cool feature of showing help for the makefile commands.&lt;/p&gt;
&lt;p&gt;I built my own version of the command, which is a little bit more verbose, but I think a little easier to read and parse. I&amp;rsquo;ve also included the original version, with a link to the source in the &lt;a href="https://github.com/dwmkerr/makefile-help"&gt;&lt;code&gt;makefile-help&lt;/code&gt;&lt;/a&gt; repo.&lt;/p&gt;
&lt;p&gt;Essentially, the code simply:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Searches for recipes - these are lines that start with text, have a colon and a hash symbol&lt;/li&gt;
&lt;li&gt;Goes through each recipe found, extracts the recipe name and documentation comment&lt;/li&gt;
&lt;li&gt;Write each of the recipe names and its documentation to the console&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="testing-scripts"&gt;Testing Scripts&lt;/h2&gt;
&lt;p&gt;I wanted to make sure that if I improve on the script over time, or add different versions, the code won&amp;rsquo;t break. There&amp;rsquo;s a test script, which is a simple shell script that runs the two help commands and assets the output is as expected.&lt;/p&gt;
&lt;p&gt;At the time of writing, the shell script looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;recipes&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;help&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;help-compact&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Some colour codes for formatting.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;green&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;32m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;red&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[1;31m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;\033[00m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Default to success for the result of tests.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; recipe in &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipes[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Create the path to the expected output file.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expected_output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;./test-cases/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;-expected-output.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; ! -f &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;red&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;FAIL&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; failed, test file &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; not found\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;make &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;cat &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expected_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;green&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;PASS&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; passed\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;red&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;FAIL&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;reset&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;recipe&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; failed\n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Return the exit code.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;result&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One thing that is nice about the tests is that they are incorporated into a GitHub Action, which runs the tests using Ubuntu, MacOS and Windows, and tests on both Bash and the generic &lt;code&gt;sh&lt;/code&gt; shell.&lt;/p&gt;
&lt;p&gt;This uses the following features of GitHub actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources"&gt;Runner Images&lt;/a&gt; - predefined images are made available by GitHub for various operating systems&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell"&gt;Shell Specificity&lt;/a&gt; - GitHub actions allow you to specify the shell used for a step&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs"&gt;GitHub Action Matrix Strategies&lt;/a&gt; - A matrix of operating systems is specified, to avoid duplicating the pipeline steps for each supported operating system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This project provides a nice template or starting point if you want to build a simple shell script with some basic testing features.&lt;/p&gt;
&lt;h2 id="further-reading"&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;If you found this interesting, you might enjoy &lt;a href="https://effective-shell.com"&gt;Effective Shell&lt;/a&gt; - My free online book of shell techniques.&lt;/p&gt;</description><category>CodeProject</category></item><item><title>Effective Shell for Beginners</title><link>https://dwmkerr.com/effective-shell-for-beginners/</link><pubDate>Tue, 21 Jan 2020 00:00:00 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-for-beginners/</guid><description>&lt;p&gt;I have rebuilt my &amp;ldquo;Effective Shell&amp;rdquo; series as an online book - it&amp;rsquo;s available now on:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://effective-shell.com"&gt;https://effective-shell.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The whole site is built from a GitHub repo at &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;github.com/dwmkerr/effective-shell&lt;/a&gt;. It is open for contributions, changes, issues and suggestions. I&amp;rsquo;ve also added a comment section to each page to get input.&lt;/p&gt;
&lt;p&gt;To keep the material as accessible as possible, I have added a new section for beginners, to help anyone who has not used a shell before. It goes over who the book is useful for, what the shell is, and how to set up your computer to work through the material:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://effective-shell.com"&gt;&lt;img src="images/effective-shell-screenshot.png" alt="Effective Shell: Screenshot" width="1024px" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All comments and suggestions are welcome!&lt;/p&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Part 7: The Subtleties of Shell Commands</title><link>https://dwmkerr.com/effective-shell-7-shell-commands/</link><pubDate>Tue, 25 Jun 2019 07:25:23 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-7-shell-commands/</guid><description>&lt;p&gt;In this chapter, we&amp;rsquo;ll take a look at the various different types of shell commands that exist and how this can affect your work.&lt;/p&gt;
&lt;p&gt;By the end of this chapter, you might even be able to make sense of the horrifying and perfectly syntactically valid code below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;which &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;where &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;what &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;whence &lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;whereis who&lt;span style="color:#66d9ef"&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-are-commands"&gt;What Are Commands?&lt;/h2&gt;
&lt;p&gt;This is &lt;em&gt;really&lt;/em&gt; important to understand! A &lt;em&gt;command&lt;/em&gt; in a shell is something you execute. It might take parameters. Generally it&amp;rsquo;ll have a form like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;command param1 param2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve already seen many commands during this series:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls &lt;span style="color:#75715e"&gt;# Show the contents of the current directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd ~ &lt;span style="color:#75715e"&gt;# Move to the user&amp;#39;s home&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat file.txt &lt;span style="color:#75715e"&gt;# Output the contents of &amp;#39;file.txt&amp;#39; to stdout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But to be an effective shell user, you must understand that not all commands are created equal. The differences between the types of commands will affect how you use them.&lt;/p&gt;
&lt;p&gt;There are four types of commands in most shells:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Executables&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Built-Ins&amp;rdquo; (which we&amp;rsquo;ll just call &lt;em&gt;builtins&lt;/em&gt; from now on)&lt;/li&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;li&gt;Aliases&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s quickly dig in and see a bit more.&lt;/p&gt;
&lt;h2 id="executables---programs"&gt;Executables - Programs&lt;/h2&gt;
&lt;p&gt;Executables are just files with the &amp;rsquo;executable&amp;rsquo; bit set&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. If I execute the &lt;code&gt;cat&lt;/code&gt; command, the shell will search for an executable named &lt;code&gt;cat&lt;/code&gt; in my &lt;code&gt;$PATH&lt;/code&gt;. If it finds it, it will run the program.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ cat file.txt
This is a simple text file
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is &lt;code&gt;$PATH&lt;/code&gt;? &lt;code&gt;$PATH&lt;/code&gt; is the standard environment variable used to define &lt;em&gt;where&lt;/em&gt; the shell should search for programs. If we temporarily &lt;em&gt;empty&lt;/em&gt; this variable, the shell won&amp;rsquo;t find the command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; cat file.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash: cat: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Normally your &lt;code&gt;$PATH&lt;/code&gt; variable will include the standard locations for Linux programs - folders such as &lt;code&gt;/bin&lt;/code&gt;, &lt;code&gt;/sbin&lt;/code&gt;, &lt;code&gt;/usr/bin&lt;/code&gt; and so on&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;If you were to print the variable, you&amp;rsquo;d see a bunch of paths (they are separated by colons; I&amp;rsquo;ve put them on separate lines for readability):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The shell will start with the &lt;em&gt;earlier&lt;/em&gt; locations and move to the later ones. This allows &lt;em&gt;local&lt;/em&gt; flavours of tools to be installed for users, which will take precedence over &lt;em&gt;general&lt;/em&gt; versions of tools.&lt;/p&gt;
&lt;p&gt;There will likely be other locations too - you might see Java folders, package manager folders and so on.&lt;/p&gt;
&lt;h2 id="executables---scripts"&gt;Executables - Scripts&lt;/h2&gt;
&lt;p&gt;Imagine we create a text file called &lt;code&gt;dog&lt;/code&gt; in the local folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;🐶 woof 🐶&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we make the file &lt;em&gt;executable&lt;/em&gt;, by running &lt;code&gt;chmod +x dog&lt;/code&gt;&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;, then we can run this just like any other program - as long as we tell the shell to look for programs in the current directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;.&amp;#34;&lt;/span&gt; dog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;🐶 woof 🐶
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More common would be to run the program by giving a path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ./dog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;🐶 woof 🐶
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or just move it to a standard location that the shell already checks for programs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ mv dog /usr/local/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ dog
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;🐶 woof 🐶
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The point is that executables don&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; to be compiled program code. If a file starts with &lt;code&gt;#!&lt;/code&gt; (the &amp;lsquo;shebang&amp;rsquo;), then the system will try to run the contents of the file with the program specified in the shebang.&lt;/p&gt;
&lt;p&gt;We will look at shebangs in greater detail in a later chapter.&lt;/p&gt;
&lt;h2 id="builtins"&gt;Builtins&lt;/h2&gt;
&lt;p&gt;OK, so we&amp;rsquo;ve seen executables. What about a command like this?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local V&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt; echo $V
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You will not find the &lt;code&gt;local&lt;/code&gt; executable anywhere on your system. It is a &lt;em&gt;builtin&lt;/em&gt; - a special command built directly into the shell program.&lt;/p&gt;
&lt;p&gt;Builtins are often highly specific to your shell. They might be used for programming (&lt;code&gt;local&lt;/code&gt; for example is used to declare a locally scoped variable), or they might be for very shell-specific features.&lt;/p&gt;
&lt;p&gt;This is where we need to take note. As soon as you are running a builtin, you are potentially using a feature that is specific to &lt;em&gt;your&lt;/em&gt; shell, rather than a program that is shared across the system and can be run by &lt;em&gt;any&lt;/em&gt; shell.&lt;/p&gt;
&lt;p&gt;Trying to programmatically execute &lt;code&gt;local&lt;/code&gt; as a process will fail - there is no executable with that name; it is purely a shell construct.&lt;/p&gt;
&lt;p&gt;So how do we know if a command is a builtin? The preferred method is to use the &lt;code&gt;type&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ type local
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local is a shell builtin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; command (which is &lt;em&gt;itself&lt;/em&gt; a builtin!) can tell you the exact type of shell command.&lt;/p&gt;
&lt;p&gt;Interestingly, you might be using more builtins than you think. &lt;code&gt;echo&lt;/code&gt; is a program, but most of the time you are not executing it when you are in a shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ type -a echo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo is a shell builtin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo is /bin/echo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By using the &lt;code&gt;-a&lt;/code&gt; flag on &lt;code&gt;type&lt;/code&gt; to show &lt;em&gt;all&lt;/em&gt; commands that match the name, we see that &lt;code&gt;echo&lt;/code&gt; is actually both a builtin &lt;em&gt;and&lt;/em&gt; a program.&lt;/p&gt;
&lt;p&gt;Many simple programs have builtin versions. The shell can execute them much faster.&lt;/p&gt;
&lt;p&gt;Some commands are a builtin so that they can function in a sensible manner. The &lt;code&gt;cd&lt;/code&gt; command changes the current directory - if we executed it as a process, it would change only the directory for the &lt;code&gt;cd&lt;/code&gt; process itself, not the shell, making it much less useful.&lt;/p&gt;
&lt;p&gt;Builtins will vary from shell to shell, but many shells are &amp;lsquo;Bash-like&amp;rsquo; - meaning they will have a set very similar to the Bash builtins, which you can see here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html"&gt;https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As should be familiar from &lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;, you can get help for builtins:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ man source &lt;span style="color:#75715e"&gt;# source is a builtin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BUILTIN&lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; BSD General Commands Manual BUILTIN&lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; builtin, !, %, &lt;span style="color:#75715e"&gt;# ...snip...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SYNOPSIS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; builtin &lt;span style="color:#f92672"&gt;[&lt;/span&gt;-options&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;args ...&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, the manual will &lt;em&gt;not&lt;/em&gt; show information on specific builtins, which is a pain. Your shell &lt;em&gt;might&lt;/em&gt; have an option to show more details - for example, in Bash you can use &lt;code&gt;help&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ help source
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source: source filename &lt;span style="color:#f92672"&gt;[&lt;/span&gt;arguments&lt;span style="color:#f92672"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Read and execute commands from FILENAME and &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;. The pathnames
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; in $PATH are used to find the directory containing FILENAME. If any
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ARGUMENTS are supplied, they become the positional parameters when
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FILENAME is executed.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But remember: &lt;code&gt;help&lt;/code&gt; is a builtin; you might not find it in all shells (you won&amp;rsquo;t find it in &lt;code&gt;zsh&lt;/code&gt;, for example). This highlights again the challenges of builtins.&lt;/p&gt;
&lt;h2 id="functions"&gt;Functions&lt;/h2&gt;
&lt;p&gt;You can define your own shell functions. We will see a lot more of this later, but let&amp;rsquo;s show a quick example for now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ restart-shell &lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; exec -l &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$SHELL&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This snippet creates a function that restarts the shell (quite useful if you are messing with shell configuration files or think you might have irreversibly goofed up your current session).&lt;/p&gt;
&lt;p&gt;We can execute this function just like any command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ restart-shell
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And running &lt;code&gt;type&lt;/code&gt; will show us that this is a function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ type restart-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;restart-shell is a &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;restart-shell &lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exec -l $SHELL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Functions are one of the most powerful shell constructs we will see; they are extremely useful for building sophisticated logic. We&amp;rsquo;re going to see them in a lot more detail later, but for now it is enough to know that they exist, and can run logic, and are run as commands.&lt;/p&gt;
&lt;h2 id="aliases"&gt;Aliases&lt;/h2&gt;
&lt;p&gt;An alias is just a shortcut. Type in a certain set of characters, and the shell will replace them with the value defined in the alias.&lt;/p&gt;
&lt;p&gt;Some common commands are actually already aliases - for example, in my &lt;code&gt;zsh&lt;/code&gt; shell, the &lt;code&gt;ls&lt;/code&gt; command is an alias:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% type -a ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is an alias &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ls -G
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is /bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I make sure that when I use the &lt;code&gt;ls&lt;/code&gt; command, the shell always expands it to &lt;code&gt;ls -G&lt;/code&gt;, which colours the output.&lt;/p&gt;
&lt;p&gt;We can quickly define aliases to save on keystrokes. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ alias k&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;kubectl&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From this point on, I can use the &lt;code&gt;k&lt;/code&gt; alias as shorthand for the &lt;code&gt;kubectl&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Aliases are far less sophisticated than functions. Think of them as keystroke savers and nothing more, and you won&amp;rsquo;t go far wrong. Aliases are not portable across shells and have certain behaviours which can make them problematic to work with, there will be an entire chapter dedicated to alisases coming up in the series.&lt;/p&gt;
&lt;h2 id="so-what"&gt;So What?&lt;/h2&gt;
&lt;p&gt;So we now hopefully have a greater understanding of the variety of shell commands. Not all commands are executables, not all of the commands we &lt;em&gt;think&lt;/em&gt; are executables necessarily are, and some commands might be more sophisticated.&lt;/p&gt;
&lt;p&gt;As a shell user, the key things to remember are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Executables are &amp;lsquo;safe&amp;rsquo; - they are programs your system can use; your shell just calls out to them.&lt;/li&gt;
&lt;li&gt;Builtins are &lt;em&gt;very&lt;/em&gt; shell-specific and usually control the shell itself&lt;/li&gt;
&lt;li&gt;Functions are powerful ways to write logic but will normally be shell-specific.&lt;/li&gt;
&lt;li&gt;Aliases are conveniences for human operators, but only in the context of an interactive shell.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To find out how a command is implemented, just use the &lt;code&gt;type -a&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ type -a cat
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat is /bin/cat
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="more-than-you-need-to-know"&gt;More than You Need to Know&lt;/h2&gt;
&lt;p&gt;OK, for the masochistic few, you might be wondering about all of the other commands and utilities you may have seen that can tell you about programs and commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;what&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whatis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;which&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whence&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whereis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;em&gt;lot&lt;/em&gt; of these are legacy and should be avoided, but for completeness sake, we&amp;rsquo;ll go through them.&lt;/p&gt;
&lt;h3 id="what"&gt;&lt;code&gt;what&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;what&lt;/code&gt; reads out special metadata embedded in a program, generally used to identify the version of source code it was built from:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ what /bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Copyright &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 1989, 1993, &lt;span style="color:#ae81ff"&gt;1994&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PROGRAM:ls PROJECT:file_cmds-272.220.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There should be almost no circumstance in which you need to use it in your day-to-day work, but you might come across it if you &lt;em&gt;meant&lt;/em&gt; to type &lt;code&gt;whatis&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="whatis"&gt;&lt;code&gt;whatis&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;whatis&lt;/code&gt; searches a local help database for text. This can be useful in tracking down manual pages:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ whatis bash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bash&lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; - GNU Bourne-Again SHell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bashbug&lt;span style="color:#f92672"&gt;(&lt;/span&gt;1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; - report a bug in bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But I can&amp;rsquo;t imagine it will be a regularly used tool by most users.&lt;/p&gt;
&lt;h3 id="which"&gt;&lt;code&gt;which&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;which&lt;/code&gt; will search your &lt;code&gt;$PATH&lt;/code&gt; to see whether an executable can be found. With the &lt;code&gt;-a&lt;/code&gt; flag, it will show all results.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ which -a vi
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/bin/vi
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/bin/vi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;which&lt;/code&gt; originated in &lt;code&gt;csh&lt;/code&gt;. It remains on many systems for compatibility but in general should be avoided due to potentially odd behaviour&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id="whence"&gt;&lt;code&gt;whence&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;whence&lt;/code&gt; was added to the Korn shell. You are unlikely to use it unless you are on systems using &lt;code&gt;ksh&lt;/code&gt;. &lt;code&gt;zsh&lt;/code&gt; also has this command, but it should be avoided and considered non-standard.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% whence brew
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/local/bin/brew
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="where"&gt;&lt;code&gt;where&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;This is a shell builtin that can provide information on commands, similar to &lt;code&gt;type&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% where ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls: aliased to ls -G
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, &lt;code&gt;type&lt;/code&gt; should be preferred, as it is more standard.&lt;/p&gt;
&lt;h3 id="whereis"&gt;&lt;code&gt;whereis&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;whereis&lt;/code&gt; is available on some systems and generally operates the same as &lt;code&gt;which&lt;/code&gt;, searching paths for an executable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% whereis ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Again, &lt;code&gt;type&lt;/code&gt; should be preferred for compatability.&lt;/p&gt;
&lt;h3 id="command"&gt;&lt;code&gt;command&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt; is defined in the POSIX standard, so should be expected to be present on most modern systems. Without arguments, it simply executes a command. With the &lt;code&gt;-v&lt;/code&gt; argument, you get a fairly machine-readable or processable response; with the &lt;code&gt;-V&lt;/code&gt; argument, you get a more human readable response:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% command -v ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias ls&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ls -G&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% command -V ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is an alias &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ls -G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;command&lt;/code&gt; can be useful in scripts, as we will see in later chapters.&lt;/p&gt;
&lt;h3 id="type"&gt;&lt;code&gt;type&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;type&lt;/code&gt; is part of the Unix standard and will be present in most modern systems. As we&amp;rsquo;ve already seen, it will identify the type of command as well as the location for an executable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% type -a ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is an alias &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; ls -G
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is /bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command can also be used to only search for paths:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% type -p ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls is /bin/ls
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In summary, avoid anything that starts with &amp;lsquo;&lt;code&gt;w&lt;/code&gt;&amp;rsquo;! These are legacy commands, generally needed only when working on older Unix machines. &lt;code&gt;type&lt;/code&gt; or &lt;code&gt;command&lt;/code&gt; should be used instead.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;We will cover permissions and modes in later chapters.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Why these names and locations? It&amp;rsquo;s a long story. The best place to start if you are intersted is the &lt;a href="https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard"&gt;Filesystem Hierarchy Standard&lt;/a&gt;.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt; changes the mode of a file; &lt;code&gt;+x&lt;/code&gt; means &amp;lsquo;add the executable bit&amp;rsquo;. This tells the operating system the file can be executed.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;a href="https://unix.stackexchange.com/questions/85249/why-not-use-which-what-to-use-then"&gt;Stack Exchange: Why not use “which”? What to use then?&lt;/a&gt;&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Part 6: Everything You Don't Need To Know About Job Control</title><link>https://dwmkerr.com/effective-shell-6-job-control/</link><pubDate>Mon, 10 Jun 2019 08:26:33 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-6-job-control/</guid><description>&lt;p&gt;&lt;em&gt;Job control&lt;/em&gt; is a feature of most shells, which is generally not particularly intuitive to work with. However, knowing the basics can help prevent you from getting yourself into a tangle, and can from time to time make certain tasks a little easier.&lt;/p&gt;
&lt;p&gt;In this chapter, we&amp;rsquo;ll look at the main features of job control, why it can be a problematic, and some alternatives.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-is-job-control"&gt;What Is Job Control?&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with an example. I am building a simple web page. It has one &lt;code&gt;index.html&lt;/code&gt; file, one &lt;code&gt;styles.css&lt;/code&gt; file, and one &lt;code&gt;code.js&lt;/code&gt; file. The &lt;code&gt;index.html&lt;/code&gt; file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;My New Project&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;styles.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;code.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;!-- Snip... --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Opening the file in a browser doesn&amp;rsquo;t quite work, as it won&amp;rsquo;t load the code or the styles. We need a web server to serve styles and code.&lt;/p&gt;
&lt;p&gt;A super-useful one-liner to run a web server on any machine with Python installed is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In fact, this is so useful that I normally &lt;em&gt;alias&lt;/em&gt; this command, so that I can just type &lt;code&gt;serve&lt;/code&gt;. We&amp;rsquo;ll see aliases in a later chapter.&lt;/p&gt;
&lt;p&gt;For now, if we run this command (you can get &lt;a href="https://github.com/dwmkerr/effective-shell/tree/master/6-job-control/sample"&gt;the three sample files here&lt;/a&gt; if you want to try this yourself), then we can open the webpage in a browser, with the styles and code loaded:&lt;/p&gt;
&lt;img src="images/website-screenshot.png" alt="Screenshot: Website" width="600" /&gt;
&lt;p&gt;We can also see that the server has served the HTML, JavaScript, and CSS files:&lt;/p&gt;
&lt;img src="images/server-screenshot.png" alt="Screenshot: Server" width="600" /&gt;
&lt;p&gt;All well and good so far.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say we want to now continue using our shell, maybe to edit the website with a terminal editor like Vim or Emacs, or we want to zip up the site, or just run any shell command&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;We have a problem. The &lt;code&gt;python&lt;/code&gt; process is still running - it&amp;rsquo;s serving the website. Our shell is essentially useless, until we stop the server. See what happens when I try to edit a file:&lt;/p&gt;
&lt;img src="images/blocked-shell.gif" alt="Demo: Blocked Shell" width="600" /&gt;
&lt;p&gt;In the example above, I try to run &lt;code&gt;vi&lt;/code&gt;, but nothing is happening. Standard input is not being read by the server and not being interpreted by the shell.&lt;/p&gt;
&lt;p&gt;I have to kill the server by hitting &lt;code&gt;Ctrl+C&lt;/code&gt; (which sends a &lt;code&gt;SIGINT&lt;/code&gt;&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; - we&amp;rsquo;ll see more about signals later), clear my screen to get rid of all of the error messages, then start again.&lt;/p&gt;
&lt;p&gt;This is obviously not optimal. Let&amp;rsquo;s look at some solutions.&lt;/p&gt;
&lt;h2 id="solution-1-start-the-server-in-the-background"&gt;Solution 1: Start the Server in the Background&lt;/h2&gt;
&lt;p&gt;In most shells, you can run a command and instruct the shell to run it in the &lt;em&gt;background&lt;/em&gt;. To do this, you end the line with an ampersand. Here&amp;rsquo;s how the example would look in this case:&lt;/p&gt;
&lt;img src="images/start-in-background.gif" alt="Demo: Starting a Background Job" width="600" /&gt;
&lt;p&gt;By ending the command with an &lt;code&gt;&amp;amp;&lt;/code&gt; ampersand symbol, we instruct the shell to run the command as a &lt;em&gt;background job&lt;/em&gt;. This means that our shell is still functional. The shell has also notified us that this command is running as a background job with a specific &lt;em&gt;job number&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt; &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;19372&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In slightly obtuse language, the shell has informed us that it has started a job in the background, with job number &lt;code&gt;1&lt;/code&gt; and that this job is currently handling the process with ID &lt;code&gt;19372&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The ampersand solution is a fairly common pattern used in day-to-day work.&lt;/p&gt;
&lt;h2 id="solution-2-move-the-server-to-the-background"&gt;Solution 2: Move the Server to the Background&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you forgot to start the command in the background. Most likely in this case you&amp;rsquo;d kill the server with &lt;code&gt;Ctrl+C&lt;/code&gt; and then start it again with the &lt;code&gt;&amp;amp;&lt;/code&gt; option. However, what if this was a large file download or a task you didn&amp;rsquo;t want to abort?&lt;/p&gt;
&lt;p&gt;In the example below, we&amp;rsquo;ll move the job to the background:&lt;/p&gt;
&lt;img src="images/move-to-background.gif" alt="Demo: Moving a Job to the Background" width="600" /&gt;
&lt;p&gt;The process is currently in the foreground, so my shell is inactive. Hitting &lt;code&gt;Ctrl+Z&lt;/code&gt; sends a &amp;lsquo;suspend&amp;rsquo; signal to the process&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;, pausing it and moving it to the background.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dissect this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Serving HTTP on 0.0.0.0 port &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;127.0.0.1 - - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;03/Jun/2019 13:38:45&lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;GET / HTTP/1.1&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; -
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;^Z
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + &lt;span style="color:#ae81ff"&gt;21268&lt;/span&gt; suspended python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The shell echos as I type, so we see &lt;code&gt;^Z&lt;/code&gt; (i.e., the &lt;code&gt;Ctrl+Z&lt;/code&gt; chord I entered). The shell responds by moving the process into a background job and suspending it.&lt;/p&gt;
&lt;p&gt;The key here is that it is &lt;em&gt;suspended&lt;/em&gt;. The process is paused. So the web server is no longer serving. If you are following with the sample, reload your browser. The webpage fails to load, as the server process is not able to respond to requests.&lt;/p&gt;
&lt;p&gt;To &lt;em&gt;continue&lt;/em&gt; the job, in the background, we use the &lt;code&gt;bg&lt;/code&gt; (&amp;lsquo;background&amp;rsquo;) command, with a &lt;em&gt;job identifier&lt;/em&gt; (which always starts with a &lt;code&gt;%&lt;/code&gt; symbol - we&amp;rsquo;ll see why soon) to tell the shell to continue the job:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% bg %1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + &lt;span style="color:#ae81ff"&gt;21268&lt;/span&gt; continued python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The shell lets us know the job is being continued, and if we load the webpage again, the content is shown as expected.&lt;/p&gt;
&lt;p&gt;As a final check, we run the &lt;code&gt;jobs&lt;/code&gt; command to see what jobs the shell is running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% jobs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + running python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And there you have it - our server is running as a background job. This is exactly what we would see if we run &lt;code&gt;jobs&lt;/code&gt; after starting the server with an &lt;code&gt;&amp;amp;&lt;/code&gt; at the end. In fact, using an &lt;code&gt;&amp;amp;&lt;/code&gt; is perhaps an easier way to remember how to continue a suspended job:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% %1 &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + &lt;span style="color:#ae81ff"&gt;21268&lt;/span&gt; continued python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the same way ending a command with &lt;code&gt;&amp;amp;&lt;/code&gt; runs it in the background, ending a job identifier with &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;em&gt;continues&lt;/em&gt; it in the background.&lt;/p&gt;
&lt;p&gt;There is at least one more way to move a job to the background&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;, but I have not yet found it useful in any scenarios, and it is overly complex to explain. See the footnote for details if you are interested.&lt;/p&gt;
&lt;h2 id="moving-background-jobs-to-the-foreground"&gt;Moving Background Jobs to the Foreground&lt;/h2&gt;
&lt;p&gt;If you have a job in the background, you can bring it back to the foreground with the &lt;code&gt;fg&lt;/code&gt; (&amp;lsquo;foreground&amp;rsquo;) command. Let&amp;rsquo;s show the jobs, with the &lt;code&gt;jobs&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% jobs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + running python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here I have a background job running a server. Any one of the following commands will bring it back to the foreground:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fg %1 &lt;span style="color:#75715e"&gt;# Explicitly bring Job 1 into the foreground&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;%1 &lt;span style="color:#75715e"&gt;# ...or in shorthand, just enter the job id...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fg &lt;span style="color:#75715e"&gt;# ...if not given an id, fg and bg assume the most recent job.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now the job is in the foreground, and you can interact with the process again however you like.&lt;/p&gt;
&lt;h2 id="cleaning-up-jobs"&gt;Cleaning Up Jobs&lt;/h2&gt;
&lt;p&gt;You might realise you cannot continue what you are doing because an old job is &lt;em&gt;still running&lt;/em&gt;. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;img src="images/kill-job.gif" alt="Demo: Cleaning Up Jobs" width="600" /&gt;
&lt;p&gt;I tried to run my web server, but there was still one running as a background job. The server failed to start because the port is in use.&lt;/p&gt;
&lt;p&gt;To clean it up, I run the &lt;code&gt;jobs&lt;/code&gt; command to list the jobs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% jobs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + suspended python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s my old web server. Note that even though it is suspended, it&amp;rsquo;ll still be blocking the port it is serving on&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;. The process is paused, but it is still holding onto all of the resources it is using.&lt;/p&gt;
&lt;p&gt;Now that I know the job identifier (&lt;code&gt;%1&lt;/code&gt; in this case), I can kill the job:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% kill %1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;1&lt;span style="color:#f92672"&gt;]&lt;/span&gt; + &lt;span style="color:#ae81ff"&gt;22843&lt;/span&gt; terminated python -m SimpleHTTPServer &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;This is why job identifiers start with a percentage sign!&lt;/em&gt; The &lt;code&gt;kill&lt;/code&gt; command I have used is not a special job control command (like &lt;code&gt;bg&lt;/code&gt; or &lt;code&gt;fg&lt;/code&gt;). It is the normal &lt;code&gt;kill&lt;/code&gt; command, which terminates a process. But shells that support job control can normally use a job identifier in place of a &lt;em&gt;process identifier&lt;/em&gt;. So rather than working out what the process identifier is that I need to kill, I can just use the job identifier&lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id="why-you-shouldnt-use-jobs"&gt;Why You Shouldn&amp;rsquo;t Use Jobs&lt;/h2&gt;
&lt;p&gt;Avoid jobs. They are not intuitive to interface with, and they suffer from some serious problems.&lt;/p&gt;
&lt;p&gt;The most obvious one is that all jobs write to the same output, meaning you can quickly get garbled output like this:&lt;/p&gt;
&lt;img src="images/output.png" alt="Screenshot: Garbled Output" width="600" /&gt;
&lt;p&gt;This is what happens when I run a job, which just outputs text every second. It&amp;rsquo;s in the background, but it&amp;rsquo;s printing all over my commands. Even running the &lt;code&gt;jobs&lt;/code&gt; command to try and find the job to stop it is difficult.&lt;/p&gt;
&lt;p&gt;Input is even more complex. If a job is &lt;em&gt;running&lt;/em&gt; in the background, but requires input, it will be &lt;em&gt;silently suspended&lt;/em&gt;. This can cause confusion.&lt;/p&gt;
&lt;p&gt;Jobs &lt;em&gt;can&lt;/em&gt; be used in scripts but must be done so with caution and could easily confuse a consumer of the script if they leave background jobs hanging around, which cannot be easily cleaned up&lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Handling errors and exit codes for jobs can be problematic, causing confusion, poor error handling, or overly complex code.&lt;/p&gt;
&lt;h2 id="how-to-escape-jobs"&gt;How to Escape Jobs&lt;/h2&gt;
&lt;p&gt;If there are two things to take away, it would be this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have started running a command in the foreground, and you don&amp;rsquo;t want to stop it and would rather move it to the background, hit &lt;code&gt;Ctrl+Z&lt;/code&gt;. Then Google &amp;ldquo;job control&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you think there is a job running in the background, and it is messing with your screen, type &lt;code&gt;fg&lt;/code&gt; to bring it to the front and kill it with &lt;code&gt;Ctrl+C&lt;/code&gt;. Repeat as needed!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In either case, if you need to do something more subtle, you can return to this reference. But the first command should allow you to get your shell back while you work out how to continue the job, and the second should kill a background job that is messing with your screen.&lt;/p&gt;
&lt;h2 id="alternatives-to-jobs"&gt;Alternatives to Jobs&lt;/h2&gt;
&lt;p&gt;If you are using any kind of modern terminal such as iTerm, Terminal or the GNOME Terminal, just open a new tab or split! Much easier.&lt;/p&gt;
&lt;p&gt;The benefit to this is that each tab gets its own standard input and output, so there&amp;rsquo;s no risk of overwriting. And of course you can hide/reveal/rearrange the tabs however you like.&lt;/p&gt;
&lt;p&gt;The traditional alternative to a job for an operator who simply wants more than one thing going on at once would be a &lt;em&gt;terminal multiplexer&lt;/em&gt;, such as &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;tmux&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/terminal-multiplexer.gif" alt="terminal-multiplexer"&gt;&lt;/p&gt;
&lt;p&gt;Multiplexers work in a very similar way to a modern graphical terminal - they manage many shell instances. The benefits to a modern terminal, such as iTerm, is that you have a very intuitive GUI and lots of features.&lt;/p&gt;
&lt;p&gt;The benefits to a multiplexer are that you can run them over SSH sessions to manage complex operations on remote machines and that they run a client-server model, meaning many people can work with many multiplexed processes (and they can persist beyond sessions).&lt;/p&gt;
&lt;p&gt;My personal preference is both - I use a modern terminal &lt;em&gt;and&lt;/em&gt; run everything inside it in &lt;code&gt;tmux&lt;/code&gt;. We&amp;rsquo;ll look at both of these options in later chapters.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference&lt;/h2&gt;
&lt;p&gt;You might find that jobs are useful, or you might find that they are not. Either way, here&amp;rsquo;s a quick reference of some common commands:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;amp;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the command as a background job.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Ctrl+Z&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move the current process into a background job, suspended.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all jobs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fg %1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move background job number 1 into the foreground.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bg %1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue background job number 1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kill %1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Terminate job number 1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wait %1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block until job number 1 exits.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you want to find out more about the gory details of jobs, the best place to start is the &lt;a href="https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Job-Control"&gt;Bash Manual - Job Control Section&lt;/a&gt;, or the &amp;lsquo;Job Control&amp;rsquo; section of your preferred shell&amp;rsquo;s manual.&lt;/p&gt;
&lt;p&gt;I hope you found this useful, and, as always, please leave comments, questions or suggestions below!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="footnotes"&gt;Footnotes&lt;/h2&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;If you are not a heavy shell user, this might seem unlikely. But if you do a lot of work in shells, such as sysadmin, devops, or do your coding from a terminal, this happens all the time!&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Signals like &lt;code&gt;SIGINT&lt;/code&gt;, &lt;code&gt;SIGKILL&lt;/code&gt;, &lt;code&gt;SIGTERM&lt;/code&gt; and so on will be covered in a later chapter.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Technically, &lt;code&gt;SIGTSTP&lt;/code&gt; - which is &amp;lsquo;TTY stop&amp;rsquo;. If you have always wondered about the &amp;lsquo;TTY&amp;rsquo; acroynm, check the previous chatper, &lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Interlude: Understanding the Shell&lt;/a&gt;.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;The alternative method is to use &lt;code&gt;Ctrl+Y&lt;/code&gt;, which will send a &lt;em&gt;delayed interrupt&lt;/em&gt;, which will continue to run the process until it tries to read from &lt;code&gt;stdin&lt;/code&gt;. At this point, the job is suspended and the control given to the shell. The operator can then use &lt;code&gt;bg&lt;/code&gt; or &lt;code&gt;kill&lt;/code&gt; or &lt;code&gt;fg&lt;/code&gt; to either move to the background, stop the process, or keep in the foreground as preferred. See: &lt;a href="https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Job-Control"&gt;https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Job-Control&lt;/a&gt;&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;Another super-useful snippet: &lt;code&gt;lsof -i -P -n | grep 8000&lt;/code&gt; to find any process that has a given port open. Another one for the aliases chapter!&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;There are times this is needed. If a job runs &lt;em&gt;many processes&lt;/em&gt; - for example, by running a pipeline - the process identifier will change as the command moves from one stage of the pipeline to the next. The job identifier will remain constant. Remember, a job is a shell &lt;em&gt;command&lt;/em&gt;, so could run many processes.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;To see how bad this can be, create a script that starts jobs, then run it. Then run the &lt;code&gt;jobs&lt;/code&gt; command to see what is running. The output might surprise you!&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Interlude: Understanding the Shell</title><link>https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/</link><pubDate>Tue, 21 May 2019 09:22:05 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/</guid><description>&lt;p&gt;This is the first &amp;lsquo;interlude&amp;rsquo; in my &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series. These interludes give some background, history or more flavour to some of the topics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This one &lt;em&gt;should&lt;/em&gt; be high-level enough for even non-technical readers to enjoy (or at least understand!). I&amp;rsquo;ve tried to make sure any term that might be unfamiliar is described in a footnote&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. For the more technical reader, it provides an important grounding on some of the key concepts relating to shells and how they work.&lt;/p&gt;
&lt;h2 id="introduction-for-the-non-technical-reader"&gt;Introduction for the Non-Technical Reader&lt;/h2&gt;
&lt;p&gt;It might come as a surprise that &lt;em&gt;many&lt;/em&gt; technical computer users (programmers, data scientists, systems administrators etc) spend a lot of time using an interface which looks like it&amp;rsquo;s from the sixties:&lt;/p&gt;
&lt;img src="images/screenshot-shell.png" alt="Diagram: The Shell" width="600px" /&gt;
&lt;p&gt;If you work with technologists, you might have seen them using an interface like this. This kind of simple, text-based interface is called a &lt;em&gt;shell&lt;/em&gt;, and it has been a common way to interface with computers ever since the first screens and keyboards were created.&lt;/p&gt;
&lt;p&gt;Given how much computing has advanced, why would people use such an interface? Just look at how much the Windows operating-system has changed over the last three decades:&lt;/p&gt;
&lt;img src="images/screenshot-windows-evolution.png" alt="Image: The Evolution of Windows" width="600px" /&gt;
&lt;p&gt;&lt;em&gt;(By Source (WP:NFCC#4), Fair use, &lt;a href="https://en.wikipedia.org/w/index.php?curid=58853841"&gt;https://en.wikipedia.org/w/index.php?curid=58853841&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why would people choose to use such an archaic interface as a shell?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typing is &lt;em&gt;fast&lt;/em&gt;: A skilled shell user can manipulate a system at dazzling speeds just using a keyboard. Typing commands is generally &lt;em&gt;much&lt;/em&gt; faster than exploring through user interfaces with a mouse&lt;/li&gt;
&lt;li&gt;Shells are &lt;em&gt;programmable&lt;/em&gt;: Users will often being programming as they work in a shell, creating scripts to automate time-consuming or repetetive processes&lt;/li&gt;
&lt;li&gt;Shells are &lt;em&gt;portable&lt;/em&gt;: A shell can be used to interface to almost any type of computer, from a mainframe to a Raspberry Pi, in a very similar way.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not all technical users will use a shell regularly, but there are many who will spend the bulk of their time in such an interface. It is such a crucial skill to be able to operate one effectively that I have been writing this series primarily to show ways to be more efficient with this kind of interface.&lt;/p&gt;
&lt;h2 id="introduction-for-the-technical-reader"&gt;Introduction for the Technical Reader&lt;/h2&gt;
&lt;p&gt;You may be familar with the shell, but it can be useful to understand some of the surrounding concepts in detail. How does a shell differ from a terminal? What is a &lt;em&gt;tty&lt;/em&gt;? How do shells really work? Hopefully as you read this article you&amp;rsquo;ll discovery something that you didn&amp;rsquo;t know about shells.&lt;/p&gt;
&lt;h2 id="lets-get-started"&gt;Let&amp;rsquo;s Get Started!&lt;/h2&gt;
&lt;p&gt;To understand what shells, terminals, command-prompts and so on are and how they relate, we need to start with the basics: how a modern computer works!&lt;/p&gt;
&lt;h2 id="a-computer-in-a-nutshell"&gt;A Computer in a Nutshell&lt;/h2&gt;
&lt;p&gt;The diagram below shows a simplified view of a typical computer:&lt;/p&gt;
&lt;img src="images/diagram1-operating-system.png" alt="Diagram: Operating System" width="600px" /&gt;
&lt;p&gt;Already there&amp;rsquo;s a lot going on.&lt;/p&gt;
&lt;p&gt;Your computer is going to have a CPU&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; and memory&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;, and almost certainly a network adapter&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt; and display adapter&lt;sup id="fnref:5"&gt;&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref"&gt;5&lt;/a&gt;&lt;/sup&gt;. Most computers will have at least one hard disk. For home PCs, there&amp;rsquo;ll also likely be a bunch of peripherals, such as a mouse, keyboard, printers, flash drives, webcams and so on.&lt;/p&gt;
&lt;h3 id="the-operating-system"&gt;The Operating System&lt;/h3&gt;
&lt;p&gt;The operating system is the piece of software installed on a computer that can interface with the &lt;em&gt;hardware&lt;/em&gt;. Without hardware, such as a CPU, memory, a network adapter, a graphics card, disk drives and so on, there&amp;rsquo;s not much that you can do with the computer. The operating system is the primary interface to this hardware. No normal programs will talk to hardware directly - the operating system abstracts this hardware away and provides a &lt;em&gt;software&lt;/em&gt; interface to it.&lt;/p&gt;
&lt;p&gt;The abstraction the operating system provides is essential. Developers don&amp;rsquo;t need to know the specifics of how to work with individual devices from different vendors; the operating system provides a standardised interface to all of this. It also handles various tasks such as making sure the system starts up properly.&lt;/p&gt;
&lt;p&gt;The operating system is generally broken down into two parts - the &lt;em&gt;kernel&lt;/em&gt; and &lt;em&gt;user space&lt;/em&gt;:&lt;/p&gt;
&lt;img src="images/diagram2-the-kernel-and-user-space.png" alt="Diagram: The Kernel and User Space" width="600px" /&gt;
&lt;p&gt;Let&amp;rsquo;s look at these in more detail.&lt;/p&gt;
&lt;h3 id="the-kernel"&gt;The Kernel&lt;/h3&gt;
&lt;p&gt;This is the part of the operating system that is responsible for the most sensitive tasks: interfacing with physical devices, managing the resources that are available for users and programs, starting up the various systems that are needed, and so on.&lt;/p&gt;
&lt;p&gt;Software running in the kernel has direct access to resources, so is &lt;em&gt;extremely&lt;/em&gt; sensitive. The kernel will balance resources between the programs in user space, which we&amp;rsquo;ll look at shortly. If you&amp;rsquo;ve ever had to install &amp;lsquo;drivers&amp;rsquo;, these are examples of pieces of software that will run in the kernel - they&amp;rsquo;ll have direct access to a physical device you&amp;rsquo;ve installed, and expose it to the rest of the software on the computer.&lt;/p&gt;
&lt;p&gt;Why &amp;lsquo;kernel&amp;rsquo;? The kernel is the soft, edible part of a nut or seed, which is surrounded by a shell. Below you can see a walnut - the kernel is the soft bit in the middle, and the shell surrounds and protects it. This is a useful metaphor that is used for parts of a computer.&lt;/p&gt;
&lt;img src="images/image-walnut.jpg" alt="Image: Photo of a walnut, showing the kernel and the shell" width="200px" /&gt;
&lt;p&gt;&lt;em&gt;(By Kkchaudhary11 - Own work, CC BY-SA 4.0, &lt;a href="https://commons.wikimedia.org/w/index.php?curid=49069244"&gt;https://commons.wikimedia.org/w/index.php?curid=49069244&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The operating system kernel really is the &lt;em&gt;core&lt;/em&gt; of the operating system. It&amp;rsquo;s such a sensitive area of the operating system that we actually want to avoid running software in it if possible&lt;sup id="fnref:6"&gt;&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref"&gt;6&lt;/a&gt;&lt;/sup&gt;. And that is where &lt;em&gt;user space&lt;/em&gt; comes in.&lt;/p&gt;
&lt;h3 id="user-space"&gt;User Space&lt;/h3&gt;
&lt;p&gt;The vast majority of programs run in &amp;lsquo;user space&amp;rsquo; (also commonly called &amp;lsquo;user land&amp;rsquo;).&lt;/p&gt;
&lt;p&gt;When a program starts, the kernel will allocate it a private segment of memory and provide &lt;em&gt;limited&lt;/em&gt; access to resources. The program is given access to a library of functions by the operating system, which it can use to access resources such as files, devices and so on. Programs in user space are essentially in sandboxes, where there is a limit to how much damage they can do.&lt;/p&gt;
&lt;p&gt;For example, a program running in user space can use the standard &lt;a href="http://man7.org/linux/man-pages/man3/fopen.3.html"&gt;&lt;code&gt;fopen&lt;/code&gt;&lt;/a&gt; function, which is provided on almost every operating system as part of the &lt;a href="https://www.gnu.org/software/libc/"&gt;C Standard Library&lt;/a&gt;. This allows a program to attempt to open a file. The operating system will make a decision on whether the program is &lt;em&gt;allowed&lt;/em&gt; to open the file (based on things such as permissions, where the file is and so on) and then, if it is OK with the call, will give the program access to the file. Under the hood, this &amp;lsquo;user space&amp;rsquo; call translates to a system call in the kernel.&lt;/p&gt;
&lt;p&gt;Now that the key components have been introduced, we can look at the &lt;em&gt;shell&lt;/em&gt;. The name should come as no surprise, as it is a &lt;em&gt;wrapper&lt;/em&gt; or outer layer to the operating system (which itself contains the sensitive nugget of the kernel).&lt;/p&gt;
&lt;h3 id="the-shell"&gt;The Shell&lt;/h3&gt;
&lt;p&gt;So what is the shell? The shell is just a general name for any &lt;em&gt;user space&lt;/em&gt; program that allows access to resources in the system, via some kind of interface.&lt;/p&gt;
&lt;p&gt;Shells come in many different flavours but are generally provided to aid a human operator in accessing the system. This could be interactively, by typing at a terminal, or via scripts, which are files that contain a sequence of commands.&lt;/p&gt;
&lt;p&gt;For example, to see all of the files in a folder, the human operator &lt;em&gt;could&lt;/em&gt; write a program in a language such as C, making system calls to do what they want. But for day-to-day tasks, this would be repetitive. A shell will normally offer us a quick way to do that exact task, without having to manually write a program to do it.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example, where a shell is being used to show the &amp;lsquo;png&amp;rsquo; images in the folder I am working in&lt;sup id="fnref:7"&gt;&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref"&gt;7&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;img src="images/screenshot1-example-shell.png" alt="Screenshot: Browsing Contents of the File System the the Bourne Again Shell" width="600px" /&gt;
&lt;p&gt;So a shell is a user-space program to interface with the computer. But there a few more moving parts than just a shell we are seeing in the image above. There are different types of shells, there are terminal programs, and there are the programs or commands that the shell calls (in the example above, &lt;code&gt;tree&lt;/code&gt; is a program). Let&amp;rsquo;s pick these apart.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a diagram that more accurately shows what is going on:&lt;/p&gt;
&lt;img src="images/diagram3-terminal-and-shell.png" alt="Diagram: The Terminal &amp; The Shell" width="600px" /&gt;
&lt;p&gt;We&amp;rsquo;ve introduced a few new things here. There&amp;rsquo;s a &lt;em&gt;user&lt;/em&gt;, who is interfacing with a &lt;em&gt;terminal&lt;/em&gt;, which is running a &lt;em&gt;shell&lt;/em&gt;, which is showing a &lt;em&gt;command prompt&lt;/em&gt;. The user has written a command that is calling a program (in this case, the &lt;code&gt;tree&lt;/code&gt; program).&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dissect this bit by bit.&lt;/p&gt;
&lt;h3 id="the-terminal"&gt;The Terminal&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;re not &lt;em&gt;directly&lt;/em&gt; interacting with the &amp;lsquo;shell&amp;rsquo; in this diagram. We&amp;rsquo;re actually using a &lt;em&gt;terminal&lt;/em&gt;. When a user wants to work with a shell interactively, using a keyboard to provide input and a display to see the output on the screen, the user uses a &lt;em&gt;terminal&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A terminal is just a program that reads input from the keyboard, passes that input to another program (normally a shell), and displays the results on the screen. A shell program on its own does not do this - it requires a terminal as an interface.&lt;/p&gt;
&lt;p&gt;Why the word &lt;em&gt;terminal&lt;/em&gt;? This makes sense when you look at how people interfaced with computers historically. Input to a computer might be through punch cards, and output would often be via a printer. The &lt;em&gt;Teletype Termimal&lt;/em&gt;&lt;sup id="fnref:8"&gt;&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref"&gt;8&lt;/a&gt;&lt;/sup&gt; became a common way for users to interface with computers.&lt;/p&gt;
&lt;img src="images/image-asr-33.jpg" alt="Photo: ASR-33 TTY" width="600px" /&gt;
&lt;p&gt;&lt;em&gt;(Photograph by Rama, Wikimedia Commons, Cc-by-sa-2.0-fr, CC BY-SA 2.0 fr, &lt;a href="https://commons.wikimedia.org/w/index.php?curid=17821795"&gt;https://commons.wikimedia.org/w/index.php?curid=17821795&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At this time, computers were very large, complex, and expensive machines. It was common to have &lt;em&gt;many&lt;/em&gt; terminals connected to a single large machine (or &amp;lsquo;mainframe&amp;rsquo;), or a few terminals that people would share. But the terminal itself was just a human interface to the operating system. A more modern terminal would be something like an IBM 3486:&lt;/p&gt;
&lt;img src="images/image-ibm3486.jpg" alt="Photo: IBM 3486" width="600px" /&gt;
&lt;p&gt;&lt;em&gt;(By ClickRick - Own work, CC BY-SA 3.0, &lt;a href="https://commons.wikimedia.org/w/index.php?curid=6693700"&gt;https://commons.wikimedia.org/w/index.php?curid=6693700&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a very small computer in its own right but still basically just a dumb screen and keyboard connected by a cable to a larger mainframe computer in another location.&lt;/p&gt;
&lt;p&gt;This mechanism is still very much the case today. When I want to work with a computer in a data centre, I don&amp;rsquo;t go and find the machine, plug in a keyboard and a display and directly interface to it. I run a &lt;em&gt;terminal program&lt;/em&gt; on my computer to provide access to the remote machine. My terminal program allows me to use my keyboard and display to work with a remote machine - all via a &lt;em&gt;secure shell&lt;/em&gt; - which is a secured-shell connection over a network.&lt;/p&gt;
&lt;p&gt;So terminals in many ways are quite simple - they are interfaces. But because they are quite simple programs, we can&amp;rsquo;t do much with them. So normally, the first thing that a terminal program will do is run a &lt;em&gt;shell&lt;/em&gt; program - a program that we can use to operate the computer.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s nothing special about terminals - anyone can write a program to operate as a terminal, which is why you will see many different terminals around. Examples are the standard &amp;rsquo;terminal&amp;rsquo; app for MacOS X, the &lt;a href="https://wiki.gnome.org/Apps/Terminal/VTE"&gt;gnome-terminal&lt;/a&gt; for Linux, and &lt;a href="https://www.iterm2.com/"&gt;iTerm2&lt;/a&gt; and &lt;a href="https://hyper.is/"&gt;Hyper&lt;/a&gt;. There&amp;rsquo;s a bunch of screenshots of different setups at the end of the article.&lt;/p&gt;
&lt;h2 id="back-to-the-shell"&gt;Back to the Shell&lt;/h2&gt;
&lt;p&gt;Now that we&amp;rsquo;ve described the terminal, we can go back and look at the shell in detail.&lt;/p&gt;
&lt;p&gt;The shell is the program that is going to take input from somewhere and run a series of commands. When the shell is running in a terminal, it is normally taking input interactively from the user. As the user types in commands, the terminal feeds the input to the shell and presents the output of the shell on the screen.&lt;/p&gt;
&lt;p&gt;A shell program can also take input from files; these files will then generally be &amp;lsquo;shell scripts&amp;rsquo;. This might be used to run automated operations, such as cleaning up certain folders when a computer starts.&lt;/p&gt;
&lt;p&gt;Shells can write output to files or other locations, and so on. You can run a shell program outside of a terminal - you just won&amp;rsquo;t be able to interface with it using a keyboard or display. And in fact, lots of operations happen in this way: automated scripts, startup tasks, installers and so on.&lt;/p&gt;
&lt;p&gt;So what else does a shell do? Most of the features are related to helping human operators work with the system more efficiently.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quickly enter commands, see the history of commands and quickly restructure commands (see &lt;a href="http://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Effective Shell - Navigating the Command Line&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Navigate through the file system, moving from folder to folder (see &lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Effective Shell - Move Around!&lt;/a&gt;), which makes it easier for an operator to navigate the file system.&lt;/li&gt;
&lt;li&gt;Chain the output of commands together - for example, taking the output of one basic program, such as the &lt;code&gt;tree&lt;/code&gt; program we saw, and writing it to a file (see &lt;a href="https://github.com/dwmkerr/effective-shell#coming-soon"&gt;Effective Shell - Understanding Pipelines&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Offer a programming language, allowing the operator to perform more complicated tasks (see &lt;a href="https://github.com/dwmkerr/effective-shell#coming-soon"&gt;Effective Shell - Basic Shell Scripting&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And a lot more! In fact, that&amp;rsquo;s what the whole &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series is about - how to get the most from these powerful programs, particularly for those who use them regularly.&lt;/p&gt;
&lt;h3 id="the-command-prompt-or-command-line"&gt;The Command Prompt or Command Line&lt;/h3&gt;
&lt;p&gt;The last part of the diagram, which we haven&amp;rsquo;t covered yet, is the &lt;em&gt;command prompt&lt;/em&gt;.&lt;/p&gt;
&lt;img src="images/diagram4-command-prompt-1.png" alt="Diagram: Command Prompt" width="300px" /&gt;
&lt;p&gt;When a &lt;em&gt;shell&lt;/em&gt; is running in &lt;em&gt;terminal&lt;/em&gt;, it knows that a human operator will be interfacing with it. So to make sure that the operator has some kind of visual hint that &lt;em&gt;they have to enter commands&lt;/em&gt;, the shell will output some kind of prompt.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve included a set of screenshots at the end of the article, just after this section, and you can see how some different command prompts look.&lt;/p&gt;
&lt;p&gt;Note that shells don&amp;rsquo;t have to use command prompts - if you use a shell program to execute a script, there will be no command prompt. Shells only show a prompt when they know they are being used interactively. Many programs which allow a user to operate interactively will show a command prompt.&lt;/p&gt;
&lt;p&gt;Shell command prompts can be customised, so they will often look different from machine to machine (for more details, see &lt;a href="https://github.com/dwmkerr/effective-shell#coming-soon"&gt;Effective Shell - Customising the Command Line&lt;/a&gt;). Below is an example that shows a &lt;em&gt;lot&lt;/em&gt; of technical information. This is from the highly popular &lt;a href="https://ohmyz.sh/"&gt;oh-my-zsh&lt;/a&gt; framework for the &amp;lsquo;Z Shell&amp;rsquo; shell, which is very popular among developers:&lt;/p&gt;
&lt;img src="images/image-ohmyzsh.jpg" alt="Image: Customised oh-my-zsh" width="600px" /&gt;
&lt;p&gt;*(Source: &lt;a href="https://ohmyz.sh/"&gt;https://ohmyz.sh/&lt;/a&gt;)&lt;/p&gt;
&lt;h3 id="shell-commands-and-different-shells"&gt;Shell Commands and Different Shells&lt;/h3&gt;
&lt;p&gt;A lot of the &amp;lsquo;commands&amp;rsquo; in a shell, such as &lt;code&gt;cat&lt;/code&gt; (which shows the contents of a file), are actually just simple programs, which will interface with the kernel. No matter what shell you use, these commands will behave the same way, because really all you are doing is calling another progam.&lt;/p&gt;
&lt;p&gt;Some commands, such as &lt;code&gt;cd&lt;/code&gt; (change directory), are built into the shell. Some commands are functions that have been defined, or aliases to other commands (for more details on commands, see &lt;a href="https://github.com/dwmkerr/effective-shell#coming-soon"&gt;Effective Shell - Commands&lt;/a&gt;). Commands will often differ between shells.&lt;/p&gt;
&lt;p&gt;Not all shells are created equal - anyone can write a shell program, maybe creating a simple interface to the computer or a highly complex one with many features. In fact, a later article in this series will look at the geneology of the most common shells.&lt;/p&gt;
&lt;p&gt;On most Unix-like systems, the default shell is a program called &lt;code&gt;bash&lt;/code&gt;, which stands for &amp;quot; Bourne Again Shell&amp;quot; (the name and history around it will be discussed at length in the later article). But there are many other shells: the C Shell, the Korn Shell, Z Shell and Fish, just to name just a few.&lt;/p&gt;
&lt;p&gt;Users and administators can configure what shell they like to use. When a terminal opens, it will immediately start the user&amp;rsquo;s preferred shell program. It is possible to change this. Different users will have different preferences, given that shells offer varying features. This can cause complexity when working with systems, as we cannot always expect every user to have the same shell, or even for the same shell to be set up consistently, as they can be extensively customised.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s review the earlier diagram again:&lt;/p&gt;
&lt;img src="images/diagram3-terminal-and-shell-1.png" alt="Diagram: The Terminal &amp; The Shell" width="600px" /&gt;
&lt;p&gt;We can see the real internals of what is going on in this &amp;ldquo;Terminal -&amp;gt; Shell -&amp;gt; Program&amp;rdquo; chain in the diagram above quite easily.&lt;/p&gt;
&lt;p&gt;Try the command &lt;code&gt;pstree -psa $$&lt;/code&gt; in a shell&lt;sup id="fnref:9"&gt;&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref"&gt;9&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;img src="images/image-psforest.png" alt="Image: Process Tree" width="600px" /&gt;
&lt;p&gt;The first &lt;code&gt;systemd&lt;/code&gt; process is the primary process for the OS - it is process number &lt;code&gt;1&lt;/code&gt;, which initialises everything else. The second &lt;code&gt;systemd&lt;/code&gt; process is the process that is running the interface for my user. We can ignore these for now; they are internals to how the operating system boots and starts processes.&lt;/p&gt;
&lt;p&gt;What is interesting is that we can see a &lt;em&gt;terminal&lt;/em&gt; (the gnome terminal), which has started my preferred &lt;em&gt;shell&lt;/em&gt; (which is &lt;code&gt;zsh&lt;/code&gt;), which is running a &lt;em&gt;command&lt;/em&gt; (the program &lt;code&gt;pstree&lt;/code&gt;). Here we can see the exact chain as shown in the diagram earlier.&lt;/p&gt;
&lt;h3 id="thats-a-wrap"&gt;That&amp;rsquo;s a Wrap!&lt;/h3&gt;
&lt;p&gt;These are the key technologies and concepts that surround a shell.&lt;/p&gt;
&lt;p&gt;If you are interested in more technical details of working with shells, then my &lt;a href="https://github.com/effective-shell"&gt;Effective Shell&lt;/a&gt; series goes into these topics in depth. The goal of this series is to help teach techniques that making working with shells more efficient.&lt;/p&gt;
&lt;p&gt;To close the article, below are some examples of different terminals, shells, command prompts and so on.&lt;/p&gt;
&lt;h4 id="example-iterm-2--tmux--zsh"&gt;Example: iTerm 2 / tmux / zsh&lt;/h4&gt;
&lt;img src="images/example-iterm-zsh.png" alt="Example: iTerm 2, tmux, zsh" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A MacOS operating system&lt;/li&gt;
&lt;li&gt;iTerm2 as the terminal program&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tmux&lt;/code&gt; running as a &amp;rsquo;terminal multiplexer&amp;rsquo; (see &lt;a href="https://github.com/dwmkerr/effective-shell#coming-soon"&gt;Effective Shell: Terminal Multiplexers&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zsh&lt;/code&gt; (Z Shell) as the shell program, using &amp;lsquo;oh my zsh&amp;rsquo;, which is easily recognised by the &lt;code&gt;%&lt;/code&gt; sign in the command prompt.&lt;/li&gt;
&lt;li&gt;A customised command line, which shows the user and folder on one line, with only the &lt;code&gt;%&lt;/code&gt; symbol below, to leave lots of space for the input commands&lt;sup id="fnref:10"&gt;&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref"&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="example-bash"&gt;Example: Bash&lt;/h4&gt;
&lt;img src="images/example-bash.png" alt="Example: Bash" width="600px" /&gt;
&lt;img src="images/example-bash-root.png" alt="Example: Bash Elevated" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Linux operating system (Ubuntu 14)&lt;/li&gt;
&lt;li&gt;The gnome terminal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash&lt;/code&gt; as the shell&lt;/li&gt;
&lt;li&gt;In the second screenshot, the user has &amp;lsquo;root privileges&amp;rsquo;, and to indicate this, &lt;code&gt;bash&lt;/code&gt; helpfully changes the default command prompt from a dollar sign to a hash sign&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="example-windows-explorer"&gt;Example: Windows Explorer&lt;/h4&gt;
&lt;img src="images/example-explorer.png" alt="Example: Windows Explorer" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Windows 10 operating system&lt;/li&gt;
&lt;li&gt;No terminal&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;explorer.exe&lt;/code&gt; program showing us a &lt;em&gt;graphical&lt;/em&gt; shell&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This looks different from previous examples. The program, which shows the familiar Windows interface, &lt;code&gt;explorer.exe&lt;/code&gt;, is in fact a shell as well, offering interactive access to the operating system and computer resources. The bulk of the Windows APIs to interact with this interface are in the &lt;a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb773177(v=vs.85).aspx"&gt;Shell Library&lt;/a&gt;. I also maintain a popular library for building extensions to the graphical Windows shell - &lt;a href="https://github.com/dwmkerr/sharpshell"&gt;sharpshell&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="example-windows-command-prompt"&gt;Example: Windows Command Prompt&lt;/h4&gt;
&lt;img src="images/example-cmd.png" alt="Example: Command Prompt" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Windows 10 operating system&lt;/li&gt;
&lt;li&gt;The command prompt terminal and shell&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Windows, the terminal and shell are combined into a single &lt;code&gt;cmd.exe&lt;/code&gt; program. There&amp;rsquo;s an excellent article on the internals - &lt;a href="https://devblogs.microsoft.com/commandline/windows-command-line-inside-the-windows-console/"&gt;Microsoft DevBlogs: Windows Command-Line: Inside the Windows Console&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="example-windows-powershell"&gt;Example: Windows PowerShell&lt;/h4&gt;
&lt;img src="images/example-powershell.png" alt="Example: Windows Powershell" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Windows 10 operating system&lt;/li&gt;
&lt;li&gt;The PowerShell terminal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PowerShell is an improvement on the &amp;lsquo;command prompt&amp;rsquo; program that was originally used in Windows, offering much more functionality for scripting and other modern shell features.&lt;/p&gt;
&lt;h4 id="example-windows-subsystem-for-linux-wsl"&gt;Example: Windows Subsystem for Linux (WSL)&lt;/h4&gt;
&lt;img src="images/example-wsl.png" alt="Example: WSL" width="600px" /&gt;
&lt;p&gt;In this example, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Windows 10 operating system&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Bash.exe&lt;/code&gt; program&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This screenshot, from &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/faq"&gt;MSDN: Frequently Asked Questions about Windows Subsystem for Linux&lt;/a&gt; shows Bash running in Windows. This is a relatively new feature at the time of writing, allowing Windows users to use a Linux interface to the PC. This is a feature that may become increasingly valuable, as in general it is challenging to write shell code that can run on Windows and Unix-like systems.&lt;/p&gt;
&lt;h2 id="share-and-discuss"&gt;Share and Discuss&lt;/h2&gt;
&lt;p&gt;If you enjoyed this article, please do share it! Feel free to include suggestions, improvements or corrections in the comments below.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Useful References&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A simple Linux kernel module, showing how basic kernel programming works in Linux: &lt;a href="https://github.com/dwmkerr/linux-kernel-module"&gt;github.com/dwmkerr/linux-kernel-module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/How-Linux-Works-2nd-Superuser/dp/1593275676"&gt;How Linux Works - Brian Ward&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unix.stackexchange.com/questions/4126/what-is-the-exact-difference-between-a-terminal-a-shell-a-tty-and-a-con/4132"&gt;StackExchange: What is the exact difference between a &amp;rsquo;terminal&amp;rsquo;, a &amp;lsquo;shell&amp;rsquo;, a &amp;rsquo;tty&amp;rsquo;, and a console?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/commandline/windows-command-line-inside-the-windows-console/"&gt;Microsoft: Inside the Windows Console&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I&amp;rsquo;d be fascinated to know if this is at all interesting to less technically inclined people, so please do go ahead and let me know in the comments!&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;CPU: central processing unit. This is the chip in the computer that does most of the work (which after many layers of abstraction eventually becomes arithmetic and sending simple instructions to other places).&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Memory is the &amp;lsquo;working space&amp;rsquo; where the state of your system is stored. If you are writing a document, the text lives in memory, until you save it, when it then gets written to a hard drive. Memory is &lt;em&gt;ephemeral&lt;/em&gt; - everything is gone when you turn off the power to it.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;This is the part of your computer that knows how to do things like connect to a WiFi network, or has a network socket you might plug a network cable into.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;This is the part of your computer you plug the screen into.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;This is because a mistake in &lt;em&gt;Kernel Mode&lt;/em&gt; programs can have disasterous effects. It could access any files, no matter who they belong do, control the hardware, install more software - almost anything. Errors in this code can cause terrible issues (like the infamous Windows &amp;lsquo;blue screen of death&amp;rsquo;), and malicious code in the kernel essentially has full access to not only all your data but also your webcam, network adapter and so on.&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;As an aside, if you are curious about the visual style of my setup or customisations that have been made, everything in my setup is available online on my &amp;lsquo;dotfiles&amp;rsquo; repo - &lt;a href="https://github.com/dwmkerr/dotfiles"&gt;github.com/dwmkerr/dotfiles&lt;/a&gt;.&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;And that&amp;rsquo;s where the &amp;lsquo;TTY&amp;rsquo; acronym you will see sometimes comes from. Enter the &lt;code&gt;ps&lt;/code&gt; command, and you&amp;rsquo;ll actually see the TTY interface each process is attached to. This is a topic that will come up later in the series.&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;&lt;code&gt;$$&lt;/code&gt; is a Bash &lt;a href="https://www.tldp.org/LDP/abs/html/internalvariables.html#PROCCID"&gt;internal variable&lt;/a&gt;. These will also be covered in a later article in the series.&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;Feel free to see my &lt;a href="https://github.com/dwmkerr/dotfiles"&gt;dotfiles&lt;/a&gt; to configure a similar setup for yourself.&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>CodeProject</category></item><item><title>Effective Shell 4: Move Around!</title><link>https://dwmkerr.com/effective-shell-4-moving-around/</link><pubDate>Mon, 11 Mar 2019 09:02:00 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-4-moving-around/</guid><description>&lt;p&gt;This is the fourth part of my &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series, a set of practical examples of ways to be more efficient with everyday tasks in the shell or at the command line.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article we&amp;rsquo;ll look at the key elements of navigation in the shell.&lt;/p&gt;
&lt;h2 id="getting-comfortable-moving-around"&gt;Getting Comfortable Moving Around&lt;/h2&gt;
&lt;p&gt;You might already spend a lot of time in the shell, running various command line programs or using tooling for development projects or operational tasks. But you might also still switch back to a more visual paradigm for working with files, directories and resources.&lt;/p&gt;
&lt;p&gt;Being able to perform everyday file and folder manipulation tasks directly from the shell can really speed up your workflow. Let&amp;rsquo;s look at some common tasks and see how we can work with them in the shell. Along the way we&amp;rsquo;ll also introduce some of the most frequently used tools and commands to work with the filesystem.&lt;/p&gt;
&lt;h2 id="where-am-i"&gt;Where Am I?&lt;/h2&gt;
&lt;p&gt;The first command to become familiar with is &lt;code&gt;pwd&lt;/code&gt; (&amp;lsquo;print working directory&amp;rsquo;). This command will echo the current absolute path. You can also use the &lt;code&gt;$PWD&lt;/code&gt; environment variable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ echo $PWD
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Depending on your shell, or your command-line setup (which we will discuss in a later chapter), you might also see your working directly on the command-line.&lt;/p&gt;
&lt;h2 id="changing-directory"&gt;Changing Directory&lt;/h2&gt;
&lt;p&gt;Most likely one of the most familiar commands out there, the &lt;code&gt;cd&lt;/code&gt; or &lt;code&gt;chdir&lt;/code&gt; function changes the current directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/users/dave
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd -
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ~
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/users/dave
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here we can see that running &lt;code&gt;cd&lt;/code&gt; with no parameters moves to the users &amp;lsquo;home&amp;rsquo; directory. This directory is always available in the &lt;code&gt;$HOME&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;cd -&lt;/code&gt; will switch &lt;em&gt;back&lt;/em&gt; to the previous directory — this is very useful if you want to quickly jump somewhere and then back again.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;~&lt;/code&gt; as an alias for the home directory, allowing you to quickly move to personal folders, with commands such as &lt;code&gt;cd ~/Downloads&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most commonly, you will specify a path when changing directory. This can be a fully qualified path, or it can be a relative path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd /dev
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ~/repos
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ./github
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can use the special link &lt;code&gt;..&lt;/code&gt;, which is a folder that points to the &lt;em&gt;parent&lt;/em&gt; directory to move &amp;lsquo;upwards&amp;rsquo;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ../../
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="exploring-a-directory"&gt;Exploring a Directory&lt;/h2&gt;
&lt;p&gt;Once we are in a directory, we will often want to see the contents. The &lt;code&gt;ls&lt;/code&gt; (&amp;ldquo;list directory contents&amp;rdquo;) command is useful here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-navigating-the-command-line LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2-clipboard-gymnastics README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3-getting-help sed.1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4-moving-around
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default, the &lt;code&gt;ls&lt;/code&gt; command will list the files and directories. We can show more information with the &lt;code&gt;-l&lt;/code&gt; (&amp;ldquo;long format&amp;rdquo;) flag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -l
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;192&lt;/span&gt; Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:01 1-navigating-the-command-line
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;160&lt;/span&gt; Oct &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; 2-clipboard-gymnastics
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;128&lt;/span&gt; Dec &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; 3-getting-help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;96&lt;/span&gt; Mar &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 15:39 4-moving-around
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;1066&lt;/span&gt; Jun &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;561&lt;/span&gt; Mar &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 15:30 README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff &lt;span style="color:#ae81ff"&gt;15707&lt;/span&gt; Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:01 sed.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can see the permissions, the link count (which is rarely particularly useful and varies from platform to platform), the owner, the group, the size and the modification date (as well as the name).&lt;/p&gt;
&lt;p&gt;We can make the sizes more human readable, and sort by size with a few more flags &lt;code&gt;-h&lt;/code&gt; (&amp;ldquo;human readable&amp;rdquo;) and &lt;code&gt;-s&lt;/code&gt; (&amp;ldquo;sort by size&amp;rdquo;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls -lhS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#ae81ff"&gt;48&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff 15K Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:01 sed.1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff 1.0K Jun &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-rw-r--r-- &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; dave staff 561B Mar &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 15:30 README.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; dave staff 192B Mar &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 16:01 1-navigating-the-command-line
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; dave staff 160B Oct &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; 2-clipboard-gymnastics
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; dave staff 128B Dec &lt;span style="color:#ae81ff"&gt;19&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2017&lt;/span&gt; 3-getting-help
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drwxr-xr-x &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; dave staff 96B Mar &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 15:39 4-moving-around
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are &lt;em&gt;lot&lt;/em&gt; of options for &lt;code&gt;ls&lt;/code&gt;. Check the chapter &lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Getting Help&lt;/a&gt; for some tips on how to get more information on a command!&lt;/p&gt;
&lt;h2 id="managing-the-directory-stack"&gt;Managing the Directory Stack&lt;/h2&gt;
&lt;p&gt;You might find that you want to move to a number of directories, then return to where you started. This can be particularly useful when scripting. You can use the &lt;code&gt;pushd&lt;/code&gt; (&amp;ldquo;push onto directory stack&amp;rdquo;) and &lt;code&gt;popd&lt;/code&gt; (&amp;ldquo;pop from directory stack&amp;rdquo;) commands to add or remove directories from the stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pwd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/Users/dave/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# OK - I&amp;#39;m writing my article at the moment, but want to check my downloads, and come back shortly...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Move to the downloads folder...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws-nuke-v2.8.0-darwin-amd64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# OK cool - the tool I was downloading has arrived, let&amp;#39;s use it...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd aws-nuke-v2.8.0-darwin-amd64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./aws-nuke
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Now I want to go back to my article...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ popd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/Downloads ~/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/Downloads
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ popd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/repos/github/dwmkerr/effective-shell
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, using &lt;code&gt;cd -&lt;/code&gt; would not be sufficient — that would just switch us from the &lt;code&gt;aws-nuke&lt;/code&gt; folder to &lt;code&gt;Downloads&lt;/code&gt; and back again. But by using the &lt;em&gt;directory stack&lt;/em&gt; we can save where we are, move, and then &amp;lsquo;pop&amp;rsquo; our way back to where we started.&lt;/p&gt;
&lt;h2 id="auto-completion"&gt;Auto-Completion&lt;/h2&gt;
&lt;p&gt;Pressing &lt;code&gt;tab&lt;/code&gt; when using commands like &lt;code&gt;cd&lt;/code&gt; will generally show an auto-completion menu:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd ~/repos/ &lt;span style="color:#75715e"&gt;# press &amp;#39;tab&amp;#39; now...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;github/ gitlab/ local/ scratch/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pressing tab again will cycle through options, and shift-tab will cycle backwards. Enter will select an option, escape (or Ctrl-C) will cancel.&lt;/p&gt;
&lt;p&gt;Some shells, such as &lt;code&gt;zsh&lt;/code&gt;, support even more advanced auto-completion. For example, we can auto-complete to fill in partially specified directory names:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% cd ~/r/g/d/e &lt;span style="color:#75715e"&gt;# press tab now...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% cd ~/repos/github/dwmkerr/effective-
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;effective-container-engineering/ effective-shell/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Auto-completion is generally &lt;em&gt;very&lt;/em&gt; shell specific. We&amp;rsquo;ll look more into the different shells that are available in later chapters. But in general, if you are uncertain, pressing tab will often show a sensible set of options.&lt;/p&gt;
&lt;h2 id="thats-it"&gt;That&amp;rsquo;s It!&lt;/h2&gt;
&lt;p&gt;This is a small chapter, but an important one. Later on, as we start to do more file and system manipulation from the shell, moving and copying files and so on, we will build on these concepts. But it is critical to first know the basics of how to move around the filesystem with the shell.&lt;/p&gt;</description><category>CodeProject</category></item><item><title>A portable and magic-free way to open Pull Requests from the Command Line</title><link>https://dwmkerr.com/a-portable-and-magic-free-way-to-open-pull-requests-from-the-command-line/</link><pubDate>Wed, 10 Oct 2018 09:17:26 +0000</pubDate><guid>https://dwmkerr.com/a-portable-and-magic-free-way-to-open-pull-requests-from-the-command-line/</guid><description>&lt;p&gt;This little bash snippet will let you open a GitHub or GitLab pull request from the command line on most Unix-like systems (OSX, Ubuntu, etc), without using any magic libraries, ZSH tricks or other dependencies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; download the &lt;a href="https://gist.github.com/dwmkerr/bae3fdca2d7208ec5d0008911d79b47d"&gt;&lt;code&gt;gpr.sh&lt;/code&gt;&lt;/a&gt; gist.&lt;/p&gt;
&lt;p&gt;&lt;img src="images/gpr.png" alt="gpr"&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks in action OSX:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/gpr.gif" alt="gpr"&gt;&lt;/p&gt;
&lt;p&gt;And Ubuntu:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/gpr-ubuntu.gif" alt="gpr-ubuntu"&gt;&lt;/p&gt;
&lt;p&gt;The script is available as the &lt;a href="https://gist.github.com/dwmkerr/bae3fdca2d7208ec5d0008911d79b47d"&gt;&lt;code&gt;gpr.sh&lt;/code&gt;&lt;/a&gt; gist. You can also find it in my &lt;a href="https://github.com/dwmkerr/dotfiles"&gt;dotfiles&lt;/a&gt;, in the &lt;a href="https://github.com/dwmkerr/dotfiles/blob/master/profile/git.sh"&gt;git.sh&lt;/a&gt; file.&lt;/p&gt;
&lt;h2 id="the-script"&gt;The Script&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the script in its entirety:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Colour constants for nicer output.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GREEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\033[0;32m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RESET&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\033[0m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Push the current branch to origin, set upstream, open the PR page if possible.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpr&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Get the current branch name, or use &amp;#39;HEAD&amp;#39; if we cannot get it.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;git symbolic-ref -q HEAD&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch##refs/heads/&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;HEAD&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Pushing take a little while, so let the user know we&amp;#39;re working.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Opening pull request for &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GREEN&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;branch&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;RESET&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Push to origin, grabbing the output but then echoing it back.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; push_output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git push origin -u &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;push_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# If there&amp;#39;s anything which starts with http, it&amp;#39;s a good guess it&amp;#39;ll be a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# link to GitHub/GitLab/Whatever. So open it.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;echo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;push_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; | grep -o &lt;span style="color:#e6db74"&gt;&amp;#39;http.*&amp;#39;&lt;/span&gt; | sed -e &lt;span style="color:#e6db74"&gt;&amp;#39;s/[[:space:]]*$//&amp;#39;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Opening: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GREEN&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;RESET&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; python -mwebbrowser &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;
&lt;p&gt;Blow-by-blow, let&amp;rsquo;s take a look.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Colour constants for nicer output.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GREEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\033[0;32m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RESET&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\033[0m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To make colouring console output easier, we create strings with the escape code required to set the &amp;lsquo;green&amp;rsquo; colour, and reset the text colour.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpr&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Get the current branch name, or use &amp;#39;HEAD&amp;#39; if we cannot get it.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;git symbolic-ref -q HEAD&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch##refs/heads/&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; branch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;HEAD&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we define the &lt;code&gt;gpr&lt;/code&gt; (Git Pull Request) function. We&amp;rsquo;ll need to push the current branch, so we need to get the current branch name. There&amp;rsquo;s plenty of discussion on how this works on &lt;a href="https://stackoverflow.com/questions/6245570/how-to-get-the-current-branch-name-in-git"&gt;Stack Overflow: How to get the current branch name in Git&lt;/a&gt;. Essentially we just get the symbolic name for the head of our current branch, which will be something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;refs/heads/my-new-branch
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We then use &lt;a href="https://www.tldp.org/LDP/abs/html/string-manipulation.html"&gt;Bash substring removal&lt;/a&gt; to rip out the &lt;code&gt;ref/heads/&lt;/code&gt; part. If we have no branch (for example, we are detached) we just use &lt;code&gt;HEAD&lt;/code&gt; a the branch name.&lt;/p&gt;
&lt;p&gt;Next we have this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Pushing take a little while, so let the user know we&amp;#39;re working.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Opening pull request for &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GREEN&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;branch&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;RESET&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Push to origin, grabbing the output but then echoing it back.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; push_output&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;git push origin -u &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;branch&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;push_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ve previously defined some strings which include the escape codes to colour terminal output. Now we just show the user the branch we&amp;rsquo;re going to push, push it and then store all of the output in the &lt;code&gt;push_output&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; idiom is a common one. This simply makes sure we put all &lt;code&gt;stderr&lt;/code&gt; output (which is always file descriptor 2) into &lt;code&gt;stdout&lt;/code&gt; (which is always file descriptor 1). This means whether the program writes output to &lt;code&gt;stdout&lt;/code&gt; or &lt;code&gt;stderr&lt;/code&gt;, we capture it. There&amp;rsquo;s a nice write-up on this in the blog post &amp;lsquo;&lt;a href="https://www.brianstorti.com/understanding-shell-script-idiom-redirect/"&gt;Understanding Shell Script&amp;rsquo;s idiom: 2&amp;gt;&amp;amp;1
&lt;/a&gt;&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;The output from Git push will be dependent on the Git server being used. For GitHub it&amp;rsquo;ll look like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;remote:
remote: Create a pull request for &amp;#39;feat/doc-cleanup&amp;#39; on GitHub by visiting:
remote: https://github.com/dwmkerr/dotfiles/pull/new/feat/doc-cleanup
remote:
To github.com:dwmkerr/dotfiles
* [new branch] feat/doc-cleanup -&amp;gt; feat/doc-cleanup
Branch feat/doc-cleanup set up to track remote branch feat/doc-cleanup from origin.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now all we want to do is see if there is any text which starts with &lt;code&gt;http&lt;/code&gt; and if there is, then open it. Here&amp;rsquo;s how we do that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# If there&amp;#39;s anything which starts with http, it&amp;#39;s a good guess it&amp;#39;ll be a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# link to GitHub/GitLab/Whatever. So open it.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;echo &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;push_output&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; | grep -o &lt;span style="color:#e6db74"&gt;&amp;#39;http.*&amp;#39;&lt;/span&gt; | sed -e &lt;span style="color:#e6db74"&gt;&amp;#39;s/[[:space:]]*$//&amp;#39;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Opening: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GREEN&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;RESET&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; python -mwebbrowser &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;link&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This uses &lt;code&gt;grep&lt;/code&gt; to rip out everything from &lt;code&gt;http&lt;/code&gt; onwards, and the &lt;code&gt;sed&lt;/code&gt; to remove any trailing whitespace. If we have found a link, we use &lt;code&gt;python&lt;/code&gt; to open it (which is a fairly safe cross-platform solution).&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it! When you have a branch ready which you want to push and create a pull request from, just run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the branch will be pushed to &lt;code&gt;origin&lt;/code&gt;, and if there is a Pull Request webpage, it&amp;rsquo;ll be opened.&lt;/p&gt;
&lt;h2 id="prior-art"&gt;Prior Art&lt;/h2&gt;
&lt;p&gt;My colleague Tobias recently shared a nice trick we worked out to open a GitLab merge request - which also now works for GitHub:&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;git push and directly open PR in Chrome - works for &lt;a href="https://twitter.com/github?ref_src=twsrc%5Etfw"&gt;@github&lt;/a&gt; &amp;amp; &lt;a href="https://twitter.com/gitlab?ref_src=twsrc%5Etfw"&gt;@gitlab&lt;/a&gt; 🚀&lt;br&gt;&lt;br&gt;Here is how to set it up 👉 &lt;a href="https://t.co/YfNTmdwTFt"&gt;https://t.co/YfNTmdwTFt&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/github?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#github&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/gitlab?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#gitlab&lt;/a&gt; &lt;a href="https://t.co/ISE9kVZmw1"&gt;pic.twitter.com/ISE9kVZmw1&lt;/a&gt;&lt;/p&gt;&amp;mdash; Tobias Büschel (@TobiasBueschel) &lt;a href="https://twitter.com/TobiasBueschel/status/1042452158430502915?ref_src=twsrc%5Etfw"&gt;September 19, 2018&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;I wanted to be able to use the same trick in Ubuntu and other Linux distros, but realised it relied on &lt;a href="https://github.com/robbyrussell/oh-my-zsh"&gt;oh-my-zsh&lt;/a&gt; and assumed OSX with Chrome as the browser, so tweaked it to the above. Thanks Tobi!&lt;/p&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Part 3: Getting Help</title><link>https://dwmkerr.com/effective-shell-part-3-getting-hepl/</link><pubDate>Tue, 19 Dec 2017 09:05:18 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-part-3-getting-hepl/</guid><description>&lt;p&gt;This is the third part of my &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series - practical examples of ways to be more efficient with everyday tasks in a shell.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article I&amp;rsquo;ll show you how to quickly get help when working with tools in the shell, without disrupting your flow!&lt;/p&gt;
&lt;h2 id="getting-help-is-important"&gt;Getting Help is Important!&lt;/h2&gt;
&lt;p&gt;If you are trying to be more effective when using the shell, it is crucial to know how to quickly look things up.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;ll be many circumstances where you&amp;rsquo;ll need to open a browser to search for help, but there&amp;rsquo;s also a wealth of information only a few keystrokes away. Looking up parameters, checking how to run commads, C library docs or useful information like ASCII charts are available directly in the system.&lt;/p&gt;
&lt;p&gt;Before we look at the standard way of accessing documentation on unix-like systems, which is the &lt;code&gt;man&lt;/code&gt; command, I&amp;rsquo;m going to introduce &lt;a href="https://github.com/tldr-pages/tldr"&gt;&lt;code&gt;tldr&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nine times out of ten I get the help I need in a few seconds with &lt;code&gt;tldr&lt;/code&gt;, so if you take only one thing away from the article, take the first section. Then if you want to learn more about the system manuals, read on!&lt;/p&gt;
&lt;h2 id="tldr"&gt;tl;dr&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say I need to find and replace some text in a file. I know I can do this with the &lt;code&gt;sed&lt;/code&gt; command, but have forgotten the syntax.&lt;/p&gt;
&lt;p&gt;All I need to do is run &lt;code&gt;tldr sed&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/tldr-sed.png" alt="tldr sed screenshot"&gt;&lt;/p&gt;
&lt;p&gt;The first example is exactly what I&amp;rsquo;m looking for. Now for any more detail than a few basic examples, I&amp;rsquo;m going to have to go to the manual, but it&amp;rsquo;s overkill for the basics. Here&amp;rsquo;s what &lt;code&gt;man sed&lt;/code&gt; shows me:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/man-sed.png" alt="sed manpage"&gt;&lt;/p&gt;
&lt;p&gt;And this is just page one of six! There&amp;rsquo;s a &lt;em&gt;lot&lt;/em&gt; of detail, which is great sometimes, but for a quick lookup, &lt;code&gt;tldr&lt;/code&gt; is perfect.&lt;/p&gt;
&lt;p&gt;You can install the &lt;a href="https://github.com/tldr-pages/tldr"&gt;&lt;code&gt;tldr&lt;/code&gt;&lt;/a&gt; tool with &lt;code&gt;npm install -g tldr&lt;/code&gt;. It&amp;rsquo;s open source and community maintained.&lt;/p&gt;
&lt;p&gt;Now a lot of the time, you are still going to need more help or more detail. For the rest of the article, we&amp;rsquo;ll dive a bit deeper into &lt;code&gt;man&lt;/code&gt;, the system manual pages.&lt;/p&gt;
&lt;h2 id="understanding-man"&gt;Understanding &amp;lsquo;man&amp;rsquo;&lt;/h2&gt;
&lt;p&gt;Most tools you encounter in the shell have manual pages available. Many people will be familiar with the &lt;code&gt;man&lt;/code&gt; command to get help on a tool, but let&amp;rsquo;s take a look in a bit more detail, there&amp;rsquo;s actually a lot more available than just the documentation for common commands.&lt;/p&gt;
&lt;h3 id="getting-help-on-a-command"&gt;Getting help on a command&lt;/h3&gt;
&lt;p&gt;The most basic way to get help on a command is with &lt;code&gt;man&lt;/code&gt;. Here&amp;rsquo;s an example:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ man cp
CP(1) BSD General Commands Manual CP(1)
NAME
cp -- copy files
SYNOPSIS
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ...
target_directory
DESCRIPTION
In the first synopsis form, the cp utility copies the contents of the
source_file to the target_file. In the second synopsis form, the con-
tents of each named source_file is copied to the destination
target_directory. The names of the files themselves are not changed. If
cp detects an attempt to copy a file to itself, the copy will fail.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;man&lt;/code&gt; command opens the manual for the given tool. These manuals should contain all command line options and details of how to use the tool.&lt;/p&gt;
&lt;p&gt;You can scroll up and down through the content with the arrow keys, this is because the information is presented in the shell &lt;em&gt;pager&lt;/em&gt;, which is a tool for looking through content which might not easily fit on a screen.&lt;/p&gt;
&lt;h3 id="using-the-pager"&gt;Using the pager&lt;/h3&gt;
&lt;p&gt;The first thing you might notice is that you can move through the manual pages with the arrow keys.&lt;/p&gt;
&lt;p&gt;Manpages are just text files, and &lt;code&gt;man&lt;/code&gt; opens them in a pager tool, which is what is providing the keyboard interface to look through the file.&lt;/p&gt;
&lt;p&gt;On most systems, the pager will be the &lt;code&gt;less&lt;/code&gt; program. There are lots of commands you can use to navigate through files with &lt;code&gt;less&lt;/code&gt;, but the bare essentials are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt; - Scroll down half a page&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u&lt;/code&gt; - Scroll up half a page&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j&lt;/code&gt; / &lt;code&gt;k&lt;/code&gt; - Scroll down or up a line. You can also use the arrow keys for this&lt;/li&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt; - Quit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&amp;lt;search&amp;gt;&lt;/code&gt; - Search for text&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt; - When searching, find the next occurrence&lt;/li&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt; - When searching, find the previous occurrence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are &lt;em&gt;many&lt;/em&gt; other commands, but the set above is normally what I find myself using the most.&lt;/p&gt;
&lt;p&gt;If you are interested, you can actually see what your pager is with the command below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ echo $PAGER
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;less
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;$PAGER&lt;/code&gt; environment variable is used to tell the shell what program to use for paging. More details are found with &lt;code&gt;man man&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can put any text content into your pager - try this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls -al /usr/bin | less
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This lists the contents of the &lt;code&gt;/usr/bin&lt;/code&gt; folder, piping the output to &lt;code&gt;less&lt;/code&gt; so we can easily scroll through it.&lt;/p&gt;
&lt;p&gt;There are alternative pagers available (on many Unix-y systems you&amp;rsquo;ll have &lt;code&gt;less&lt;/code&gt;, &lt;code&gt;more&lt;/code&gt; and &lt;code&gt;most&lt;/code&gt;) but in general you&amp;rsquo;ll normally get what you need with &lt;code&gt;less&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="whats-with-the-numbers"&gt;What&amp;rsquo;s with the numbers?&lt;/h3&gt;
&lt;p&gt;You&amp;rsquo;ll often see tools referred to in manpages with numbers after them. Take a look at &lt;code&gt;man less&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/numbers.png" alt="Screenshot of numbers"&gt;&lt;/p&gt;
&lt;p&gt;The number is the manual &lt;strong&gt;Section Number&lt;/strong&gt;. The different sections of the manual are documented be found on most unix-like systems in &lt;code&gt;man&lt;/code&gt;&amp;rsquo;s documentation, which you can check by running &lt;code&gt;man man&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. Here&amp;rsquo;s what you&amp;rsquo;d get on Ubuntu 16:&lt;/p&gt;
&lt;p&gt;| 1 | Executable programs or shell commands |
| 2 | System calls (functions provided by the kernel) |
| 3 | Library calls (functions within program libraries) |
| 4 | Special files (usually found in /dev) |
| 5 | File formats and conventions eg /etc/passwd |
| 6 | Games |
| 7 | Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) |
| 8 | System administration commands (usually only for root) |
| 9 | Kernel routines [Non standard] |&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll go through the setions in detail shorltly.&lt;/p&gt;
&lt;p&gt;You can specifically choose &lt;em&gt;which&lt;/em&gt; section of the manual you are looking in by using:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;man &amp;lt;section&amp;gt; &amp;lt;search&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can also get more information about the sections themselves by opening up the &lt;code&gt;intro&lt;/code&gt; page. For example:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ man 1 intro
INTRO(1) BSD General Commands Manual INTRO(1)
NAME
intro -- introduction to general commands (tools and utilities)
DESCRIPTION
Section one of the manual contains most of the commands which comprise...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Why would you do this, and why would you care? A few examples from each section show how this can be quite useful to know about.&lt;/p&gt;
&lt;h4 id="section-1-programs-and-shell-commands"&gt;Section 1: Programs and Shell Commands&lt;/h4&gt;
&lt;p&gt;These are programs, probably what you are going to be looking up most regularly! For example, &lt;code&gt;man 1 time&lt;/code&gt; shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;TIME(1) BSD General Commands Manual TIME(1)
NAME
time -- time command execution
SYNOPSIS
time [-lp] utility
DESCRIPTION
The time utility executes and times utility. After the utility finishes, time writes the total time
elapsed, the time consumed by system overhead, and the time used to execute utility to the standard
error stream. Times are reported in seconds.
...
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="section-2-system-calls"&gt;Section 2: System Calls&lt;/h4&gt;
&lt;p&gt;You&amp;rsquo;ll probably not use this section unless you are doing systems programming&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;. This section contains info on the avaiable Linux Kernel system calls. For example, running &lt;code&gt;man 2 chown&lt;/code&gt; gives:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CHOWN(2) BSD System Calls Manual CHOWN(2)
NAME
chown, fchown, lchown, fchownat -- change owner and group of a file
SYNOPSIS
#include &amp;lt;unistd.h&amp;gt;
int
chown(const char *path, uid_t owner, gid_t group);
...
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="section-3-library-calls"&gt;Section 3: Library Calls&lt;/h4&gt;
&lt;p&gt;These are the manpages for the C standard library functions. For example, &lt;code&gt;man 3 time&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;TIME(3) BSD Library Functions Manual TIME(3)
NAME
time -- get time of day
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include &amp;lt;time.h&amp;gt;
time_t
time(time_t *tloc);
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we can see why the sections are important to know about.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;man time&lt;/code&gt; would &lt;em&gt;not&lt;/em&gt; open the page above, because &lt;code&gt;man&lt;/code&gt; searches the library in ascending section order, meaning that it actually finds &lt;code&gt;time(1)&lt;/code&gt; and shows the pages for the &lt;code&gt;time&lt;/code&gt; program, not the &lt;code&gt;time&lt;/code&gt; C library call.&lt;/p&gt;
&lt;p&gt;Because of the potential ambiguity of names if no section number is included, in lots of Linux documentation you&amp;rsquo;ll see the man section number written next to library calls, system calls, programs and so on (things will refer to &lt;code&gt;sed(1)&lt;/code&gt; or &lt;code&gt;time(3)&lt;/code&gt; for example.&lt;/p&gt;
&lt;h4 id="section-4-devices"&gt;Section 4: Devices&lt;/h4&gt;
&lt;p&gt;This section deals with the special devices which live in the &lt;code&gt;/dev/*&lt;/code&gt; folder. For example, running &lt;code&gt;man 4 random&lt;/code&gt; shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;RANDOM(4) BSD Kernel Interfaces Manual RANDOM(4)
NAME
random , urandom -- random data source devices.
SYNOPSIS
pseudo-device random
DESCRIPTION
The random device produces uniformly distributed random byte values of
potentially high quality.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Again, we see that section numbers can be important. If you just run &lt;code&gt;man random&lt;/code&gt;, you&amp;rsquo;ll see:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;RANDOM(3) BSD Library Functions Manual RANDOM(3)
NAME
initstate, random, setstate, srandom, srandomdev -- better random num-
ber generator; routines for changing generators
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include &amp;lt;stdlib.h&amp;gt;
char *
initstate(unsigned seed, char *state, size_t size);
long
random(void);
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which is the manpage for &lt;code&gt;random(3)&lt;/code&gt;, which is C library function, not the &lt;code&gt;/dev/random&lt;/code&gt; file!&lt;/p&gt;
&lt;h4 id="section-5-file-formats"&gt;Section 5: File Formats&lt;/h4&gt;
&lt;p&gt;This section details special files in the system. For example, &lt;code&gt;man 5 crontab&lt;/code&gt; shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CRONTAB(5) BSD File Formats Manual CRONTAB(5)
NAME
crontab -- tables for driving cron
DESCRIPTION
A crontab file contains instructions to the cron(8) daemon of the gen-
eral form: ``run this command at this time on this date&amp;#39;&amp;#39;. Each user
has their own crontab, and commands in any given crontab will be exe-
cuted as the user who owns the crontab. Uucp and News will usually
have their own crontabs, eliminating the need for explicitly running
su(1) as part of a cron command.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which describes the crontab file used to define scheduled tasks. Again, this is different to &lt;code&gt;man crontab&lt;/code&gt; which would document &lt;code&gt;crontab(1)&lt;/code&gt;. Similarly, &lt;code&gt;man 5 passwd&lt;/code&gt; is going to show something quite different to &lt;code&gt;man passwd&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="section-6-games"&gt;Section 6: Games&lt;/h4&gt;
&lt;p&gt;Nothing says it better than &lt;code&gt;man 6 intro&lt;/code&gt; itself (this&amp;rsquo;ll not work on a Mac sadly, but try it on another Linux system):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;...
DESCRIPTION
Section 6 of the manual describes all the games and funny little programs available on the system.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are probably a few silly programs available on your system, here you&amp;rsquo;ll find their manuals. For example, &lt;code&gt;man 6 banner&lt;/code&gt; on a Mac shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BANNER(6) BSD Games Manual BANNER(6)
NAME
banner -- print large banner on printer
SYNOPSIS
banner [-d] [-t] [-w width] message ...
DESCRIPTION
Banner prints a large, high quality banner on the standard output. If
the message is omitted, it prompts for and reads one line of its stan-
dard input.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This section is going to be highly dependent on your OS!&lt;/p&gt;
&lt;h4 id="section-7-miscellaneous"&gt;Section 7: Miscellaneous&lt;/h4&gt;
&lt;p&gt;This is where you&amp;rsquo;ll find additional assorted documentation. For example, &lt;code&gt;man 7 ascii&lt;/code&gt; shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ASCII(7) BSD Miscellaneous Information Manual ASCII(7)
NAME
ascii -- octal, hexadecimal and decimal ASCII character sets
DESCRIPTION
The octal set:
000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel
...
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="section-8-system-commands"&gt;Section 8: System Commands&lt;/h4&gt;
&lt;p&gt;We&amp;rsquo;ve actually already seen one of these commands mentioned, in the manpage for &lt;code&gt;crontab(5)&lt;/code&gt; it mentions &lt;code&gt;cron(8)&lt;/code&gt;. Let&amp;rsquo;s see, with &lt;code&gt;man 8 cron&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CRON(8) BSD System Manager&amp;#39;s Manual CRON(8)
NAME
cron -- daemon to execute scheduled commands (Vixie Cron)
SYNOPSIS
cron [-s] [-o] [-x debugflag[,...]]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are commands which sysadmins would normally run. You might open section eight unexpectedly, for example &lt;code&gt;man chmod&lt;/code&gt; will open &lt;code&gt;chmod(1)&lt;/code&gt;, but &lt;code&gt;man chown&lt;/code&gt; will open &lt;code&gt;chown(8)&lt;/code&gt;, as it is a system command.&lt;/p&gt;
&lt;p&gt;Some distributions might vary for Section Nine. On my Mac it contains information about the kernel interfaces, a C style guide and some more.&lt;/p&gt;
&lt;h4 id="getting-the-index-of-manual-section"&gt;Getting the Index of Manual Section&lt;/h4&gt;
&lt;p&gt;Manpages are just files on the filesystem, so you can get the index of a section just by looking in the appropriate folder.&lt;/p&gt;
&lt;p&gt;For example, to index the available system calls, try &lt;code&gt;ls /usr/share/man/man2&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;EV_SET.2
FD_CLR.2
FD_COPY.2
FD_ISSET.2
FD_SET.2
FD_ZERO.2
_exit.2
accept.2
access.2
acct.2
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is quick and easy way to see what sort of entries you have on your system. If you want to work out where an entry lives, use the &lt;code&gt;-w&lt;/code&gt; flag:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ man -w printf
/usr/share/man/man1/printf.1
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="searching-the-manual"&gt;Searching the Manual&lt;/h3&gt;
&lt;p&gt;You can search the manpage titles and summaries with &lt;code&gt;man -k&lt;/code&gt;. For example, &lt;code&gt;man -k cpu&lt;/code&gt; shows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cpuwalk.d(1m) - Measure which CPUs a process runs on. Uses DTrace
dispqlen.d(1m) - dispatcher queue length by CPU. Uses DTrace
gasm(n), grammar::me::cpu::gasm(n) - ME assembler
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can find more advanced options for searching by using your newfound &lt;code&gt;man&lt;/code&gt; skills on &lt;code&gt;man&lt;/code&gt; itself.&lt;/p&gt;
&lt;h2 id="thats-enough"&gt;That&amp;rsquo;s Enough!&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;d recommend &lt;code&gt;tldr&lt;/code&gt; as a first-call for checking to see how to use a command.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;man&lt;/code&gt; is a powerful tool to dive deeper into how programs and components of the system work. Like many tools which have been around for a long time, there&amp;rsquo;s a lot you can do with &lt;code&gt;man&lt;/code&gt;. Much of it you&amp;rsquo;ll likely never need, so I&amp;rsquo;ve tried to keep this article to the basics.&lt;/p&gt;
&lt;p&gt;Understanding manpage sections is useful - you&amp;rsquo;ll see them referenced again and again in documentation on the system and online.&lt;/p&gt;
&lt;p&gt;I hope this helps you save some time when you are working! Please let me know in the comments if you have any questions or thoughts.&lt;/p&gt;
&lt;p&gt;You can also check out the &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;rest of the effective shell series&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="appendix-dash"&gt;Appendix: Dash&lt;/h2&gt;
&lt;p&gt;As a final note, if you find yourself using &lt;code&gt;man&lt;/code&gt; a lot because you work offline (I fly a lot so find it very helpful when on a plane with no WiFi), you should also look at &lt;em&gt;Dash&lt;/em&gt;&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Dash is simply an offline documentation aggregator. It can download online manuals for many, many different programming languages, frameworks, technologies and so on. I actually have a &lt;code&gt;vim&lt;/code&gt; keyboard command to open the word under the cursor in dash, with the documentation automatically set based on the type of the file.&lt;/p&gt;
&lt;p&gt;This is super-useful if you are offline at lot and need more sophisticated offline documentation. You can find out more about it at &lt;a href="https://kapeli.com/dash"&gt;https://kapeli.com/dash&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="footnotes"&gt;Footnotes&lt;/h2&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Weirdly satisfying to run.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Which it is always fun to try if you get the chance, and a great way to learn more about the fundamentals of the operating system.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Dash is a paid product. Full disclosure - I don&amp;rsquo;t get any money from them or anyone else to write about anything, all content is 100% based on my experiences. I don&amp;rsquo;t run ads on my site either.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Part 2: Become a Clipboard Gymnast</title><link>https://dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/</link><pubDate>Tue, 10 Oct 2017 09:57:54 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/</guid><description>&lt;p&gt;This is the second part of my &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;Effective Shell&lt;/a&gt; series, which contains practical tips for using the shell to help with every day tasks and be more efficient:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article I&amp;rsquo;ll show you how you can use the shell as an efficient tool to compliment how you use the clipboard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note for Linux Users: In this article I&amp;rsquo;ll use the &lt;code&gt;pbcopy&lt;/code&gt; and &lt;code&gt;pbpaste&lt;/code&gt; commands to access the clipboard, which are available on a Mac only. To get access to the same commands on other platforms, check &lt;a href="#appendixclipboardaccessonlinux"&gt;Appendix: Clipboard Access on Linux&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="use-the-shell-on-the-clipboard"&gt;Use the Shell on the Clipboard&lt;/h2&gt;
&lt;p&gt;You can easily use shell commands on the contents of your clipboard. Just use &lt;code&gt;pbpaste&lt;/code&gt; to output the clipboard, run the output through some commands, then use &lt;code&gt;pbcopy&lt;/code&gt; to copy the result.&lt;/p&gt;
&lt;p&gt;Try copying the following text:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Kirk Van Houten
Timothy Lovejoy
Artie Ziff
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then in the shell, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pbpaste
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You should see the contents of the clipboard. Now we&amp;rsquo;ll look at some ways that shell access to the clipboard can help with common tasks.&lt;/p&gt;
&lt;h2 id="removing-formatting"&gt;Removing Formatting&lt;/h2&gt;
&lt;p&gt;Don&amp;rsquo;t you hate it when you have to copy formatted text and don&amp;rsquo;t have an easy way to paste it as &lt;em&gt;unformatted&lt;/em&gt; text? Here&amp;rsquo;s an example, I want to copy this Wikipedia page on &amp;lsquo;bash&amp;rsquo;, and paste it into a Word document:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/strip-formatting-before.png" alt="Copying and pasting with formatting"&gt;&lt;/p&gt;
&lt;p&gt;Many programs have a shortcut to paste the contents of the clipboard (such as &amp;lsquo;command + shift + v&amp;rsquo;) but if you are like me you might find yourself pasting &lt;em&gt;into&lt;/em&gt; a plain text editor just to copy &lt;em&gt;out&lt;/em&gt; the plain text.&lt;/p&gt;
&lt;p&gt;If you just run the command &lt;code&gt;pbpaste | pbcopy&lt;/code&gt;, you can easily strip the formatting:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/strip-formatting-after-2.png" alt="Stripping formatting from the clipboard"&gt;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re just piping out the clipboard (which ends up as plain text, cause we&amp;rsquo;re in a terminal!) and then piping that plain text &lt;em&gt;back into the clipboard&lt;/em&gt;, replacing the formatted text which was there before.&lt;/p&gt;
&lt;p&gt;This little trick can be very useful. But we can use the same pattern to quickly manipulate the contents of the clipboard in more sophisticated ways.&lt;/p&gt;
&lt;h2 id="manipulating-text"&gt;Manipulating Text&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say someone has emailed me a list of people I need to invite to an event:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/email_list_excel.png" alt="Email List"&gt;&lt;/p&gt;
&lt;p&gt;The problem is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The list is in Excel and is formatted&lt;/li&gt;
&lt;li&gt;The list has duplicates&lt;/li&gt;
&lt;li&gt;I need to turn each name into an email address like &amp;lsquo;&lt;a href="mailto:Artie_Ziff@simpsons.com"&gt;Artie_Ziff@simpsons.com&lt;/a&gt;&amp;rsquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And I want to email everyone quickly.&lt;/p&gt;
&lt;p&gt;We can quickly handle this task without leaving the shell.&lt;/p&gt;
&lt;p&gt;Copy the raw text below if you want to try out the same commands and follow along:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Artie Ziff
Kirk Van Houten
Timothy Lovejoy
Artie Ziff
Nick Riviera
Seymore Skinner
Hank Scorpio
Timothy Lovejoy
John Frink
Cletus Spuckler
Ruth Powers
Artie Ziff
Agnes Skinner
Helen Lovejoy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First, we copy the text to the clipboard.&lt;/p&gt;
&lt;p&gt;Now we can paste and sort:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pbpaste | sort
Agnes Skinner
Artie Ziff
Artie Ziff
Artie Ziff
Cletus Spuckler
Hank Scorpio
Helen Lovejoy
John Frink
Kirk Van Houten
Nick Riviera
Ruth Powers
Seymore Skinner
Timothy Lovejoy
Timothy Lovejoy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then remove the duplicates:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pbpaste | sort | uniq
Agnes Skinner
Artie Ziff
Cletus Spuckler
Hank Scorpio
Helen Lovejoy
John Frink
Kirk Van Houten
Nick Riviera
Ruth Powers
Seymore Skinner
Timothy Lovejoy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Replace the underscore with an ampersand:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pbpaste | sort | uniq | tr &amp;#34; &amp;#34; &amp;#34;_&amp;#34;
Agnes_Skinner
Artie_Ziff
Cletus_Spuckler
Hank_Scorpio
Helen_Lovejoy
John_Frink
Kirk_Van_Houten
Nick_Riviera
Ruth_Powers
Seymore_Skinner
Timothy_Lovejoy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then add the final part of the email address:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pbpaste | sort | uniq | tr &amp;#34; &amp;#34; &amp;#34;_&amp;#34; | sed &amp;#39;s/$/@simpsons.com/&amp;#39;
Agnes_Skinner@simpsons.com
Artie_Ziff@simpsons.com
Cletus_Spuckler@simpsons.com
Hank_Scorpio@simpsons.com
Helen_Lovejoy@simpsons.com
John_Frink@simpsons.com
Kirk_Van_Houten@simpsons.com
Nick_Riviera@simpsons.com
Ruth_Powers@simpsons.com
Seymore_Skinner@simpsons.com
Timothy_Lovejoy@simpsons.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This looks perfect! We can now put the transformed text back onto the clipboard:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ pbpaste | sort | uniq | tr &amp;#39; &amp;#39; &amp;#39;_&amp;#39; | sed &amp;#39;s/$/@simpsons.com&amp;#39; | pbcopy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All in all we have the following pipeline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pbpaste&lt;/code&gt; - output the clipboard&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sort&lt;/code&gt; - order the output&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uniq&lt;/code&gt; - deduplicate the rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tr ' ' '_'&lt;/code&gt; - replace spaces with underscores&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sed /$/@simpsons.com&lt;/code&gt; - add the email domain to the end of the row&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Building this in one go is hard, let&amp;rsquo;s look at little more at the pipeline.&lt;/p&gt;
&lt;h2 id="thinking-in-pipelines"&gt;Thinking in Pipelines&lt;/h2&gt;
&lt;p&gt;Some of these commands might be unfamiliar, some might not make sense, and you might be thinking &amp;lsquo;how would I remember that&amp;rsquo;. Actually, there are many ways to solve the problem above, this is the one I came up with by &lt;em&gt;iteratively&lt;/em&gt; changing my input text.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what I mean - you&amp;rsquo;ll see that I actually build a pipeline like this step-by-step:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/pipeline.gif" alt="Animation of the process of building a pipeline"&gt;&lt;/p&gt;
&lt;p&gt;You can see in the screenshots that I start simple, and step by step add the stages we need.&lt;/p&gt;
&lt;p&gt;(P.S - if you are wondering how I am jumping backwards and forwards a word at a time, check the last chapter &amp;lsquo;&lt;a href="www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Navigating the Command Line&lt;/a&gt;&amp;rsquo;).&lt;/p&gt;
&lt;p&gt;What we&amp;rsquo;re doing here is only possible because these simple commands all follow &amp;rsquo;the Unix Philosophy&amp;rsquo;. They do one thing well, and each command expects it&amp;rsquo;s input to become the input of &lt;em&gt;another&lt;/em&gt; command later on. Specifically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The commands are primitive and simple - &lt;code&gt;sort&lt;/code&gt; is sorting a list, &lt;code&gt;uniq&lt;/code&gt; is making elements unique.&lt;/li&gt;
&lt;li&gt;The commands don&amp;rsquo;t produce unnecessary output - &lt;code&gt;sort&lt;/code&gt; doesn&amp;rsquo;t add a header such as &lt;code&gt;Sorted Items&lt;/code&gt;, which is great because otherwise it would clutter our pipeline.&lt;/li&gt;
&lt;li&gt;We are chaining commands together, the output of one becomes the input of another.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We don&amp;rsquo;t need a command such as &amp;lsquo;Take a muddy list, sort and clean it, then turn pairs of words into an email address&amp;rsquo; - with a few simple &amp;lsquo;workhorse&amp;rsquo; commands we can easily build this functionality ourselves.&lt;/p&gt;
&lt;p&gt;These workhorse commands will be introduced and detailed as we go through the series. We&amp;rsquo;ll also spend a lot more time looking at pipelines.&lt;/p&gt;
&lt;p&gt;I hope this was useful! Please comment if you have any questions or tips. To see further articles as they come out, follow the repo at:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/effective-shell"&gt;github.com/dwmkerr/effective-shell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or just follow &lt;a href="https://twitter.com/dwmkerr"&gt;@dwmkerr&lt;/a&gt; on Twitter.&lt;/p&gt;
&lt;h1 id="appendix---clipboard-access-on-linux"&gt;Appendix - Clipboard Access on Linux&lt;/h1&gt;
&lt;p&gt;If you are using Linux, there is no &lt;code&gt;pbcopy&lt;/code&gt; and &lt;code&gt;pbpaste&lt;/code&gt; commands. You can use the &lt;a href="https://linux.die.net/man/1/xclip"&gt;&lt;code&gt;xclip&lt;/code&gt;&lt;/a&gt; tool to create equivalent commands.&lt;/p&gt;
&lt;p&gt;First, install &lt;code&gt;xclip&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install -y xclip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then add the following to your &lt;code&gt;.bashrc&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create mac style aliases for clipboard access.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias pbcopy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xclip -selection c&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias pbpaste&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xclip -selection c -o&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Obviously you can use any alias you like! The article assumes that &lt;code&gt;pbcopy&lt;/code&gt; and &lt;code&gt;pbpaste&lt;/code&gt; have been used.&lt;/p&gt;</description><category>CodeProject</category></item><item><title>Effective Shell Part 1: Navigating the Command Line</title><link>https://dwmkerr.com/effective-shell-part-1-navigating-the-command-line/</link><pubDate>Sun, 11 Jun 2017 23:05:40 +0000</pubDate><guid>https://dwmkerr.com/effective-shell-part-1-navigating-the-command-line/</guid><description>&lt;p&gt;This is the &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;first part of a series&lt;/a&gt; I am writing which contains practical tips for using the shell more effectively.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-1-navigating-the-command-line/"&gt;Part 1: Navigating the Command Line&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-2-become-a-clipboard-gymnast/"&gt;Part 2: Become a Clipboard Gymnast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dwmkerr.com/effective-shell-part-3-getting-hepl/"&gt;Part 3: Getting Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-4-moving-around/"&gt;Part 4: Moving Around&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/"&gt;Part 5: Interlude - Understanding the Shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-6-job-control/"&gt;Part 6: Everything You Don&amp;rsquo;t Need to Know About Job Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dwmkerr.com/effective-shell-7-shell-commands/"&gt;Part 7: The Subtleties of Shell Commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can&amp;rsquo;t think of a better place to start than &lt;em&gt;navigating the command line&lt;/em&gt;. As you start to do more and more in the shell, text in the command line can quickly become hard to handle. In this article I&amp;rsquo;ll show some simple tricks for working with the command line more effectively.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a quick reference diagram, the rest of the article goes into the details!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/effective-shell"&gt;&lt;img src="images/command-line-3.png" alt="command line"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article, examples and diagrams are available at &lt;a href="https://github.com/dwmkerr/effective-shell"&gt;github.com/dwmkerr/effective-shell&lt;/a&gt;.&lt;/p&gt;
&lt;!-- TOC depthFrom:2 depthTo:3 withLinks:1 updateOnSave:1 orderedList:0 --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#basicnavigation"&gt;Basic Navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#searching"&gt;Searching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#editinginplace"&gt;Editing In-Place&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#clearthescreen"&gt;Clear the Screen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#protipallthekeys"&gt;Pro Tip: All The Keys!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#protiptransposing"&gt;Pro Tip: Transposing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#closingthoughts"&gt;Closing Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- /TOC --&gt;
&lt;h2 id="basic-navigation"&gt;Basic Navigation&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s assume we have a very simple command we are writing, which is going to write a quote to a text file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;The trouble with writing fiction is that it has to make sense,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;whereas real life doesn&amp;#39;t. -- Iain M. Banks&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; quote.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Navigating around long lines of text is a slow process if you are only relying on the arrow keys, so take the time to learn the following shortcuts:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Go to beginning / end&lt;/td&gt;
&lt;td&gt;&lt;p&gt;&lt;code&gt;Ctrl + a&lt;/code&gt;, &lt;code&gt;Ctrl + e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/begin-end.gif" target="_blank"&gt;&lt;img src="images/begin-end.gif" alt="begin / end" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go backwards / forwards one word&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt + b&lt;/code&gt; / &lt;code&gt;Alt + f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/forward-backwards.gif" target="_blank"&gt;&lt;img src="images/forward-backwards.gif" alt="backward / forward" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete a word / undo&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl + w&lt;/code&gt; / &lt;code&gt;Ctrl + -&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/delete-undo.gif" target="_blank"&gt;&lt;img src="images/delete-undo.gif" alt="delete / undo" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete next word&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt + d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/delete-next-word.gif" target="_blank"&gt;&lt;img src="images/delete-next-word.gif" alt="delete next word" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete all the way to the beginning[^1]&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl + u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/delete-to-beginning.gif" target="_blank"&gt;&lt;img src="images/delete-to-beginning.gif" alt="delete to beginning" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete all the way to the end&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl + k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/delete-to-end.gif" target="_blank"&gt;&lt;img src="images/delete-to-end.gif" alt="delete to end" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that if you are on a Mac, you might need to tweak your console to allow the &amp;lsquo;Alt&amp;rsquo; key to work.&lt;/p&gt;
&lt;p&gt;For iTerm2, go to settings (Command + ,) &amp;gt; Profiles Tab &amp;gt; select the profile you are using &amp;gt; Keys tab. There, you should see Left Option key and Right Option Key with three radio buttons. Select &amp;ldquo;Esc+&amp;rdquo; for the Left Option Key.&lt;/p&gt;
&lt;p&gt;For Terminal, go to Profiles Tab &amp;gt; Keyboard Tab &amp;gt; check &amp;ldquo;Use Option as Meta key&amp;rdquo; at the bottom of the screen.&lt;/p&gt;
&lt;h2 id="searching"&gt;Searching&lt;/h2&gt;
&lt;p&gt;Once you have the basic navigation commands down, the next essential is searching. Let&amp;rsquo;s assume we&amp;rsquo;ve run the following three commands:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ command1 param1 param2 param3
$ command2 param4 param5 param6
$ command3 param7 param8 param9
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can search backwards or forwards with &lt;code&gt;Ctrl + r&lt;/code&gt; and &lt;code&gt;Ctrl + s&lt;/code&gt;. This will search in the current command and then iteratively through previous commands:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/search-backwards-and-forwards.gif" alt="search backwards and forwards"&gt;&lt;/p&gt;
&lt;p&gt;This is useful for searching in the current command, but can be also used to quickly search backwards and forwards through the command history:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/search-commands-backwards-and-forwards-1.gif" alt="search commands backwards and forwards"&gt;&lt;/p&gt;
&lt;p&gt;As you type, your command history is searched, the most recent commands coming first. Use the arrow keys to edit the command, press enter to execute it, or &lt;code&gt;Ctrl + g&lt;/code&gt; to cancel the search.&lt;/p&gt;
&lt;p&gt;Here are the same commands applied to the original example:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Search backwards / forwards&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl + r&lt;/code&gt; / Ctrl + s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/search-history-next.gif" target="_blank"&gt;&lt;img src="images/search-history-next.gif" alt="find next occurrence" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run the command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/search-history-execute.gif" target="_blank"&gt;&lt;img src="images/search-history-execute.gif" alt="execute" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edit the command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Right Arrow&lt;/code&gt; / &lt;code&gt;Right Arrow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/search-history-edit.gif" target="_blank"&gt;&lt;img src="images/search-history-edit.gif" alt="edit command" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop searching&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl + g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="images/search-history-cancel.gif" target="_blank"&gt;&lt;img src="images/search-history-cancel.gif" alt="cancel search" style="max-width:100%;"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id="editing-in-place"&gt;Editing In-Place&lt;/h2&gt;
&lt;p&gt;These tips and tricks are helpful, but if you are working with a really long or complex command, you might find it useful just to jump into your favourite editor.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;Ctrl + x , Ctrl + e&lt;/code&gt; to edit-in place:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/edit-in-place.gif" alt="edit in place"&gt;&lt;/p&gt;
&lt;p&gt;In a later article I&amp;rsquo;ll talk a little more about how to configure the default editor.&lt;/p&gt;
&lt;h2 id="clear-the-screen"&gt;Clear the Screen&lt;/h2&gt;
&lt;p&gt;Probably the shortcut I use the most is &lt;code&gt;Ctrl + l&lt;/code&gt;, which clears the screen without trashing your current command. Here&amp;rsquo;s how it looks:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/clear-screen-2.gif" alt="clear screen"&gt;&lt;/p&gt;
&lt;h2 id="pro-tip-all-the-keys"&gt;Pro Tip: All The Keys!&lt;/h2&gt;
&lt;p&gt;You can use the &lt;code&gt;bindkey&lt;/code&gt; command to see a list of all keyboard shortcuts:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ bindkey
&amp;#34;^@&amp;#34; set-mark-command
&amp;#34;^A&amp;#34; beginning-of-line
&amp;#34;^B&amp;#34; backward-char
&amp;#34;^D&amp;#34; delete-char-or-list
&amp;#34;^E&amp;#34; end-of-line
&amp;#34;^F&amp;#34; forward-char
&amp;#34;^G&amp;#34; send-break
&amp;#34;^H&amp;#34; backward-delete-char
&amp;#34;^I&amp;#34; expand-or-complete
&amp;#34;^J&amp;#34; accept-line
&amp;#34;^K&amp;#34; kill-line
&amp;#34;^L&amp;#34; clear-screen
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is an extremely useful command to use if you forget the specific keyboard shortcuts, or just want to see the shortcuts which are available.&lt;/p&gt;
&lt;h2 id="pro-tip-transposing"&gt;Pro Tip: Transposing!&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve mastered all of the commands here and feel like adding something else to your repertoire, try this:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/transpose-word.gif" alt="transpose-word"&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Alt + t&lt;/code&gt; shortcut will transpose the last two words. Use &lt;code&gt;Ctrl + t&lt;/code&gt; to transpose the last two letters:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/transpose-letters.gif" alt="transpose-letters"&gt;&lt;/p&gt;
&lt;p&gt;These were new to me when I was researching for this article. I can&amp;rsquo;t see myself ever being able to remember the commands more quickly than just deleting the last two words or characters and re-typing them, but there you go!&lt;/p&gt;
&lt;h2 id="closing-thoughts"&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;If you are ever looking to go deeper, then search the web for &lt;em&gt;GNU Readline&lt;/em&gt;, which is the library used under the hood to handle the command line in many shells. You can actually configure lower level details of how all shells which use readline work, with the &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File.html"&gt;&lt;code&gt;.inputrc&lt;/code&gt;&lt;/a&gt; configuration file.&lt;/p&gt;
&lt;p&gt;The great thing about learning these shortcuts is that they will work in any prompt which uses GNU Readline. This means everything you&amp;rsquo;ve learnt applies to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bash&lt;/li&gt;
&lt;li&gt;zsh&lt;/li&gt;
&lt;li&gt;The Python REPL&lt;/li&gt;
&lt;li&gt;The Node.js REPL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And probably a whole bunch more&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;All of these shortcuts should be familiar to Emacs users. There is in fact a &amp;lsquo;Vi Mode&amp;rsquo; option for readline, which allows you to use vi commands to work with text. You can enter this mode with &lt;code&gt;set -o vi&lt;/code&gt;, I&amp;rsquo;ll likely come back to this in detail in a later article.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a great cheat sheet on emacs readline commands at &lt;a href="http://readline.kablamo.org/emacs.html"&gt;readline.kablamo.org/emacs&lt;/a&gt;, which is a very useful reference if you want to dig deeper. For this article I&amp;rsquo;ve tried to focus on what I think are the most useful commands (and transpose just so you can show off!).&lt;/p&gt;
&lt;p&gt;Hope that was useful! GIFs were made with &lt;a href="http://www.cockos.com/licecap/"&gt;LICEcap&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="footnotes"&gt;Footnotes&lt;/h4&gt;
&lt;h4 id="references"&gt;References&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/GNU_Readline"&gt;Wikipedia: GNU Readline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File.html"&gt;GNU Org: Readline Init File&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://readline.kablamo.org/emacs.html"&gt;Kablamo.org: Readline Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;If you know of any more, please let me know and I&amp;rsquo;ll update the article!&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>CodeProject</category></item><item><title>Simple Continuous Integration for Docker Images</title><link>https://dwmkerr.com/simple-continuous-integration-for-docker-images/</link><pubDate>Thu, 03 Nov 2016 05:14:35 +0000</pubDate><guid>https://dwmkerr.com/simple-continuous-integration-for-docker-images/</guid><description>&lt;p&gt;In this article I&amp;rsquo;m going to demonstrate a few tips and tricks which can make your life easier when you are building or maintaining Dockerfiles.&lt;/p&gt;
&lt;h2 id="the-need-for-a-build-pipeline"&gt;The need for a Build Pipeline&lt;/h2&gt;
&lt;p&gt;Do we really need any kind of continuous integration or build pipeline for Dockerfiles?&lt;/p&gt;
&lt;p&gt;There will be cases when the answer is no. However, if the answer to any of the following questions is &amp;lsquo;yes&amp;rsquo;, it might be worth considering:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do you want others to be able to contribute to the Dockerfile, perhaps changing the image over time?&lt;/li&gt;
&lt;li&gt;Are there specific functionalities in your Dockerfiles which could break if altered?&lt;/li&gt;
&lt;li&gt;Do you expect to need to release updates to your Dockerfile?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Essentially, if we are looking at providing some kind of automated quality assurance and automation around building and releasing, then a build pipeline is not a bad idea.&lt;/p&gt;
&lt;h2 id="a-simple-build-pipeline"&gt;A simple Build Pipeline&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what a simple build pipeline could look like. This example is for a Docker Image I just created for local DynamoDB development - &lt;a href="https://github.com/dwmkerr/docker-dynamodb"&gt;dwmkerr/docker-dynamodb&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/Simple-Docker-Image-CI.png" alt="Simple Continous Intergration Pipeline"&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dissect what we&amp;rsquo;ve got here.&lt;/p&gt;
&lt;h3 id="the-dockerfile"&gt;The Dockerfile&lt;/h3&gt;
&lt;p&gt;This is the main &amp;lsquo;code&amp;rsquo; of the project if you like. The &lt;a href="https://github.com/dwmkerr/docker-dynamodb/blob/master/Dockerfile"&gt;Dockerfile&lt;/a&gt; is the recipe for the image we create.&lt;/p&gt;
&lt;h3 id="the-continuous-integration-service"&gt;The Continuous Integration Service&lt;/h3&gt;
&lt;p&gt;In this case, I am using &lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt;, however the approach described would work fine with most CI systems (such as Jenkins, TravisCI and TeamCity). There &lt;em&gt;is&lt;/em&gt; an option to use the &lt;a href="https://docs.docker.com/docker-hub/builds/"&gt;Docker Hub Automated Builds&lt;/a&gt;, but I&amp;rsquo;ve found this doesn&amp;rsquo;t give the flexibility I need (see &lt;a href="#appendix1whynotdockerhubautomatedbuilds"&gt;Why not Docker Hub Automated Builds&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Essentially the CI service needs to offer the option to have three distinct steps in the pipeline, each of which must pass for process to proceed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Deploy&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="the-build"&gt;The Build&lt;/h3&gt;
&lt;p&gt;We can build with tools, script files, whatever. At the moment, I am leaning towards &lt;a href="https://www.gnu.org/software/make/"&gt;makefiles&lt;/a&gt;. Normally I only need a few lines of shell script to do a build - anything more complex and the makefile can call a shell script. See also &lt;a href="#appendix2whymakefiles"&gt;Why Makefiles?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what it might look like:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;build:
docker build -t dwmkerr/dynamodb:latest .
ifndef BUILD_NUM
$(warning No build number is defined, skipping build number tag.)
else
docker build -t dwmkerr/dynamodb:$(BUILD_NUM) .
endif
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This command just builds the &lt;code&gt;Dockerfile&lt;/code&gt; and tags it as &lt;code&gt;dwmkerr/dynamodb:lastest&lt;/code&gt;. If a &lt;code&gt;BUILD_NUM&lt;/code&gt; variable is present, we also create the tag &lt;code&gt;dwmkerr/dynamodb:BUILD_NUM&lt;/code&gt;. This means if we want to deploy to a service such as &lt;a href="https://aws.amazon.com/ecs/"&gt;Amazon ECS&lt;/a&gt; we can push a specific build by referring to the image with that tag.&lt;/p&gt;
&lt;h3 id="the-tests"&gt;The Tests&lt;/h3&gt;
&lt;p&gt;Again I&amp;rsquo;m relying on &lt;code&gt;make&lt;/code&gt;. I just want to be able to run &lt;code&gt;make test&lt;/code&gt; - if zero is returned I&amp;rsquo;m happy. If not, the pipeline should stop and I&amp;rsquo;ll check the output. Here&amp;rsquo;s my test command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;test: build
./test/basics.test.sh
./test/ephemeral.test.sh
./test/persistent.test.sh
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Not a thing of beauty, but it works. These scripts I&amp;rsquo;ll discuss a little bit later on, in the delightly titled &lt;a href="#appendix3whatarethesetestscripts"&gt;What are these test scripts&lt;/a&gt; section.&lt;/p&gt;
&lt;p&gt;For CircleCI, this is enough to have the main part of our pipeline. Here&amp;rsquo;s how the &lt;code&gt;circle.yml&lt;/code&gt; file looks at this stage:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;machine:
services:
- docker
environment:
# Set the build number, used in makefiles.
BUILD_NUM: $CIRCLE_BUILD_NUM
test:
override:
- make test
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(Actually there&amp;rsquo;s a couple of other bits but they&amp;rsquo;re just to make sure circle uses the right version of Docker, &lt;a href="https://github.com/dwmkerr/docker-dynamodb/blob/master/circle.yml"&gt;see the full circle.yml file here&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id="the-deployments"&gt;The Deployments&lt;/h3&gt;
&lt;p&gt;Deployments are trivial as all we need to do is push to the Docker Hub. The &lt;code&gt;make deploy&lt;/code&gt; command looks-a like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;deploy:
docker push dwmkerr/dynamodb:latest
ifndef BUILD_NUM
$(warning No build number is defined, skipping push of build number tag.)
else
docker push dwmkerr/dynamodb:$(BUILD_NUM)
endif
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;rsquo;re pushing the &lt;code&gt;latest&lt;/code&gt; tag and &lt;code&gt;BUILD_NUM&lt;/code&gt; tag if present. To add this to the CircleCI pipeline, we just add the following to &lt;code&gt;circle.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;deployment:
master:
branch: master
commands:
- docker login -e $DOCKER_EMAIL -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
- make deploy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we have a push to &lt;code&gt;master&lt;/code&gt;, we log in to Docker (using environment variables I configure in the CircleCI UI) and then run &lt;code&gt;make deploy&lt;/code&gt; to push our images.&lt;/p&gt;
&lt;h2 id="thats-it"&gt;That&amp;rsquo;s It&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s about it. This is a pretty simple approach, you can see it in action at:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dwmkerr/docker-dynamodb"&gt;github.com/dwmkerr/docker-dynamodb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The rest of this post is a bit of a deep dive into some specific areas I found interesting.&lt;/p&gt;
&lt;h2 id="appendix-1-why-not-docker-hub-automated-builds"&gt;Appendix 1: Why not Docker Hub Automated Builds?&lt;/h2&gt;
&lt;p&gt;There are automated builds available in the Docker Hub:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/dockerhubbuilds.png" alt="Docker Hub Automated Builds"&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not using this feauture at the moment, here&amp;rsquo;s a brief roundup of what I think are the current pros and cons:&lt;/p&gt;
&lt;p&gt;Pros&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don&amp;rsquo;t have to goof around installing Docker on a CI platform.&lt;/li&gt;
&lt;li&gt;It allows you to update the description of your Docker image automatically, from the GitHub &lt;code&gt;README.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It allows you to associate the image with a specific GitHub repo (rather than just linking from the image description).&lt;/li&gt;
&lt;li&gt;Branch management - allowing tags to be built for specific branches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It doesn&amp;rsquo;t &lt;em&gt;seem&lt;/em&gt; to support any kind of configurable gating, such as a running a test command prior to deploying.&lt;/li&gt;
&lt;li&gt;It doesn&amp;rsquo;t &lt;em&gt;seem&lt;/em&gt; to support any kind of triggering of downstream processes, such as updating environments, sending notifications or whatever.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The lack of ability to perform tests on the image before deploying it why I&amp;rsquo;m currently not using the service.&lt;/p&gt;
&lt;p&gt;By doing the testing in a CI system for every pull request and only merging PRs where the tests pass we could mitigate the risk here. This service is worth watching as I&amp;rsquo;m sure it will evolve quickly.&lt;/p&gt;
&lt;h2 id="appendix-2-why-makefiles"&gt;Appendix 2: Why Makefiles?&lt;/h2&gt;
&lt;p&gt;I started coding with a commandline compiler in DOS. When I used my first GUI (Borland Turbo C++) it felt like a huge leap:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/turbocpp.png" alt="Borland Turbo C++"&gt;&lt;/p&gt;
&lt;p&gt;Later on I moved onto Microsoft Visual C++ 4.2:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/visualcpp.png" alt="Visual C++ 4.2"&gt;&lt;/p&gt;
&lt;p&gt;And you cannot imagine the excitement when I got my boxed edition of Visual Studio .NET:&lt;/p&gt;
&lt;p&gt;&lt;img src="images/visualstudiodotnet.jpg" alt="Visual Studio .NET"&gt;&lt;/p&gt;
&lt;p&gt;Wow!&lt;/p&gt;
&lt;p&gt;Anyway, I digress. GNU &lt;code&gt;make&lt;/code&gt; was invented by Leonardo Da Vinci in 1473 to allow you to build something from the commandline, using a fairly consistent syntax.&lt;/p&gt;
&lt;p&gt;It is near ubiquitous on *nix systems. I am increasingly using it as an &amp;rsquo;entry point&amp;rsquo; to builds, as I use variety of languages and platforms. Being able to know that most of the time:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;make build
make test
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Will build and test something is convenient. Makefiles actually are not that great to work with (see &lt;a href="http://stackoverflow.com/questions/448910/makefile-variable-assignment"&gt;this&lt;/a&gt;, &lt;a href="http://stackoverflow.com/questions/10121182/multiline-bash-commands-in-makefile"&gt;this&lt;/a&gt; and &lt;a href="http://www.conifersystems.com/whitepapers/gnu-make/"&gt;this&lt;/a&gt;). I&amp;rsquo;ve found as long as you keep the commands simple, they&amp;rsquo;re OK. For anything really complex, I normally have a &lt;code&gt;scripts/&lt;/code&gt; folder, but call the scripts &lt;em&gt;from&lt;/em&gt; the makefile, so that there&amp;rsquo;s still a simple entrypoint.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not entirely sold on makefiles, but they tend to be my default at the moment if I know I&amp;rsquo;m going to use the commandline for builds (for example, in Java projects I&amp;rsquo;ll often write a makefile to call Maven or Gradle).&lt;/p&gt;
&lt;p&gt;For things like Node.js, where you have commands like &lt;code&gt;npm test&lt;/code&gt; or &lt;code&gt;npm run xyz&lt;/code&gt; I &lt;em&gt;still&lt;/em&gt; sometimes use makefiles, using &lt;code&gt;npm&lt;/code&gt; for day-to-day dev tests (&lt;code&gt;npm start&lt;/code&gt;) and &lt;code&gt;make&lt;/code&gt; if it&amp;rsquo;s something more complex (e.g. &lt;code&gt;make deploy-sit&lt;/code&gt; to deploy to an SIT environment).&lt;/p&gt;
&lt;h2 id="appendix-3-what-are-these-test-scripts"&gt;Appendix 3: What are these test scripts?&lt;/h2&gt;
&lt;p&gt;You may have noticed:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;test: build
./test/basics.test.sh
./test/ephemeral.test.sh
./test/persistent.test.sh
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What&amp;rsquo;s going on here?&lt;/p&gt;
&lt;p&gt;My Docker image is just a wrapper around &lt;a href="http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html"&gt;Amazon&amp;rsquo;s Local DynamoDB tool&lt;/a&gt;. I don&amp;rsquo;t really need to test that tool. But what I wanted to test was the capabilities which lie at the &lt;em&gt;intersection&lt;/em&gt; between &amp;rsquo;native&amp;rsquo; Docker and &amp;rsquo;native&amp;rsquo; DynamoDB.&lt;/p&gt;
&lt;p&gt;For example, I know Docker supports volume mapping. I know DynamoDB supports using a data directory, to allow persistent between runs. I want to test I can combine Docker volume mapping and the DynamoDB data directory features. I know Docker images should default to being ephemeral, I want to test this holds true by default for my image.&lt;/p&gt;
&lt;p&gt;Testing Docker is a little hard - I want to test that I can run containers, start, stop, check state before and after and so on. This is essentially an integration test, it can be tricky to make it truly isolated and deterministic.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve given it my best go with these scripts. Here&amp;rsquo;s an example for the &amp;rsquo;ephemeral&amp;rsquo; test, where I&amp;rsquo;m trying to assert that if I run a container, create a table, stop the container and run a new one, I no longer have the table. Here&amp;rsquo;s the test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Bomb if anything fails.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Kill any running dynamodb containers.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;Cleaning up old containers...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker ps -a | grep dwmkerr/dynamodb | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt; | xargs docker rm -f &lt;span style="color:#f92672"&gt;||&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run the container.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;Checking we can run the container...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;docker run -d -p 8000:8000 dwmkerr/dynamodb&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sleep &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create a table.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws dynamodb --endpoint-url http://localhost:8000 --region us-east-1 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; create-table &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --table-name Supervillains &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --attribute-definitions AttributeName&lt;span style="color:#f92672"&gt;=&lt;/span&gt;name,AttributeType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;S &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --key-schema AttributeName&lt;span style="color:#f92672"&gt;=&lt;/span&gt;name,KeyType&lt;span style="color:#f92672"&gt;=&lt;/span&gt;HASH &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --provisioned-throughput ReadCapacityUnits&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1,WriteCapacityUnits&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Clean up the container. On CircleCI the FS is BTRFS, so this might fail...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#34;Stopping and restarting...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker stop $ID &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker rm $ID &lt;span style="color:#f92672"&gt;||&lt;/span&gt; true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;docker run -d -p 8000:8000 dwmkerr/dynamodb&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sleep &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# List the tables - there shouldn&amp;#39;t be any!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COUNT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;aws dynamodb --endpoint-url http://localhost:8000 --region us-east-1 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; list-tables &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | jq &lt;span style="color:#e6db74"&gt;&amp;#39;.TableNames | length&amp;#39;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $COUNT -ne &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Expected to find no tables, found &lt;/span&gt;$COUNT&lt;span style="color:#e6db74"&gt;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s a bit dirty - it removes containers from the host, changes things and so on. But it works.&lt;/p&gt;
&lt;p&gt;I did experiment with running these tests &lt;em&gt;in a container&lt;/em&gt;, which has the benefit of giving you a clean host to start with, which you can throw away after each test.&lt;/p&gt;
&lt;p&gt;I had to give up after a little while due to time constraints, but will probably revisit this process. The benefits of running these integration tests in a container is that we get a degree of isolation from the host.&lt;/p&gt;
&lt;p&gt;If anyone is interested, my attempts so far are on this &lt;a href="https://github.com/dwmkerr/docker-dynamodb/pull/2"&gt;RFC Pull Request&lt;/a&gt;. Feel free to jump in!&lt;/p&gt;</description><category>CodeProject</category></item><item><title>Quick Tip: Sending Newlines with cURL</title><link>https://dwmkerr.com/quick-tip-sending-newlines-with-curl/</link><pubDate>Tue, 03 May 2016 22:12:28 +0000</pubDate><guid>https://dwmkerr.com/quick-tip-sending-newlines-with-curl/</guid><description>&lt;p&gt;Yikes, this took far too long to figure out!&lt;/p&gt;
&lt;p&gt;I have a service which takes plain text multi-line input and outputs an object for each line, something like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Line 1
Line 2
Line 3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[
{line: &amp;#34;Line 1&amp;#34;},
{line: &amp;#34;Line 2&amp;#34;},
{line: &amp;#34;Line 3&amp;#34;}
]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;rsquo;s a bit more to it than that, but that&amp;rsquo;s the gist.&lt;/p&gt;
&lt;p&gt;I want to test my service with cURL, trying:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl --data &amp;#34;Line 1\nLine 2\nLine 3&amp;#34; \
-H &amp;#34;Content-Type: text/plain&amp;#34; localhost:3000/parse
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This did not work. Nor did some alternatives. And I really didn&amp;rsquo;t want to have to write the text to a file and load it in.&lt;/p&gt;
&lt;p&gt;Turns out there&amp;rsquo;s a nice little shell trick to let you use escape characters C style, use &lt;code&gt;$'some\ncontent'&lt;/code&gt; to use ANSI C escaping. Now you can cURL with newlines!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl --data $&amp;#39;Line 1\nLine 2\nLine 3&amp;#39; \
-H &amp;#34;Content-Type: text/plain&amp;#34; localhost:3000/parse
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html"&gt;GNU Bash ANSI C Quoting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/8467424/echo-newline-in-bash-prints-literal-n"&gt;Stack Overflow - Echo Newline Bash Prints \n&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/3872427/how-to-send-line-break-with-curl"&gt;Stack Overflow - How to send line break with cURL&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><category>CodeProject</category></item></channel></rss>