<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/shell/</id>
  <link href="https://www.endpointdev.com/blog/tags/shell/"/>
  <link href="https://www.endpointdev.com/blog/tags/shell/" rel="self"/>
  <updated>2025-07-10T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Bash expansion techniques for a more efficient workflow</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/07/bash-expansion-techniques/"/>
      <id>https://www.endpointdev.com/blog/2025/07/bash-expansion-techniques/</id>
      <published>2025-07-10T00:00:00+00:00</published>
      <author>
        <name>Seth Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/07/bash-expansion-techniques/mirrored-buildings.webp&#34; alt=&#34;A low-angle view of a brick building with half height walls creating an alternating pattern of wall and dark, shaded ceiling. mirrored about the center of the image. Each mirrored side of the image has two strong angles; the building protrudes from midway up the left edge, turning sharply down, then coming back up and to the right to the center.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2025. --&gt;
&lt;p&gt;For any project, you need a quick and efficient way to wrangle your files. If you use Unix, Bash and Zsh are powerful tools to help achieve this.&lt;/p&gt;
&lt;p&gt;I recently needed to rename a file so that all its underscores were replaced with dash characters, to match the convention of the project. I could do this manually pretty quickly, but I knew there was a bash built-in one-liner waiting to be discovered, so I went down the rabbit hole to learn about Bash&amp;rsquo;s &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html&#34;&gt;shell expansions&lt;/a&gt; and &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/History-Interaction.html&#34;&gt;history expansion&lt;/a&gt;. See the &amp;ldquo;history expansion&amp;rdquo; section for how I solved the underscore/dash issue.&lt;/p&gt;
&lt;p&gt;Bash has seven types of expansion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;brace expansion&lt;/li&gt;
&lt;li&gt;tilde expansion&lt;/li&gt;
&lt;li&gt;parameter and variable expansion&lt;/li&gt;
&lt;li&gt;command substitution&lt;/li&gt;
&lt;li&gt;arithmetic expansion&lt;/li&gt;
&lt;li&gt;word splitting&lt;/li&gt;
&lt;li&gt;filename expansion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The documentation is good and concise for each of these, so rather than try to recreate it, I&amp;rsquo;ll go over examples of how I use some of them.&lt;/p&gt;
&lt;h3 id=&#34;shell-parameter-expansion&#34;&gt;Shell parameter expansion&lt;/h3&gt;
&lt;h4 id=&#34;example-batch-converting-images-to-webp&#34;&gt;Example: batch converting images to WebP&lt;/h4&gt;
&lt;p&gt;I use parameter expansion frequently while maintaining this blog. We serve images in &lt;a href=&#34;/blog/2014/01/webp-images-experiment-on-end-point/&#34;&gt;WebP format&lt;/a&gt;, so I generally loop over all the JPEGs and/or PNGs (after cropping and/or scaling) and convert them using &lt;a href=&#34;https://developers.google.com/speed/webp/docs/cwebp&#34;&gt;cwebp&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f in *.png; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cwebp -q &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;80&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$f&lt;/span&gt; -o &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;f&lt;/span&gt;%.png&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;.webp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes use of parameter expansion (&lt;code&gt;${}&lt;/code&gt;) and the &lt;code&gt;%&lt;/code&gt; character, which deletes the shortest occurrence of the &lt;em&gt;word&lt;/em&gt; it precedes (&lt;code&gt;png&lt;/code&gt;) from the end of the &lt;em&gt;parameter&lt;/em&gt; (&lt;code&gt;$f&lt;/code&gt;, the filename). Then, you can insert a string immediately after the expansion and Bash will concatenate them together, making a new output filename.&lt;/p&gt;
&lt;p&gt;If you use &lt;code&gt;%%&lt;/code&gt; instead, it deletes the longest occurrence of the &lt;em&gt;word&lt;/em&gt; from the end, instead of the shortest. This would only apply if you are doing &lt;a href=&#34;https://www.gnu.org/software///bash/manual/bash.html#Pattern-Matching&#34;&gt;pattern matching&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can use the &lt;code&gt;#&lt;/code&gt; character to remove a &lt;em&gt;word&lt;/em&gt; from the beginning of the string, conversely to how &lt;code&gt;%&lt;/code&gt; removes a match from the end.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The formal definition of &lt;em&gt;word&lt;/em&gt; in &lt;a href=&#34;https://www.gnu.org/software///bash/manual/bash.html&#34;&gt;the Bash manual&lt;/a&gt; is &amp;ldquo;A sequence of characters treated as a unit by the shell. Words may not include unquoted metacharacters.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I looked this up so I would know the distinction between &lt;em&gt;words&lt;/em&gt; and &lt;a href=&#34;https://www.gnu.org/software///bash/manual/bash.html#Shell-Parameters&#34;&gt;&lt;em&gt;parameters&lt;/em&gt;&lt;/a&gt;. Parameters are more specific: mainly just variables, positional parameters, and a few special parameters.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;alternate-method-with-parameter-expansion-search-and-replace&#34;&gt;Alternate method with parameter expansion search and replace&lt;/h4&gt;
&lt;p&gt;As a bonus, my co-worker Josh showed me how he uses search and replace to solve the same problem. Note that this is parameter expansion search and replace, which has different syntax from history expansion search and replace (shown two examples down). Also, they both search for a &lt;em&gt;pattern&lt;/em&gt;, not a regular expression, so &lt;code&gt;.&lt;/code&gt; will match the literal &lt;code&gt;.&lt;/code&gt; character, etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f in *.png; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cwebp -q &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;80&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$f&lt;/span&gt; -o &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;f&lt;/span&gt;/png/webp&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;I use that version much more often than the &lt;code&gt;%&lt;/code&gt;, as it (at least to me) makes it more clear what&amp;rsquo;s happening when doing a string replacement. Also, it doesn&amp;rsquo;t do anything if &lt;code&gt;png&lt;/code&gt; isn&amp;rsquo;t found, whereas the above &lt;code&gt;%&lt;/code&gt; method always appends &lt;code&gt;.webp&lt;/code&gt;&amp;hellip; Which may be better anyway, depending on what you want to happen in that case. :)&lt;/p&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;example-counting-file-endings&#34;&gt;Example: counting file endings&lt;/h4&gt;
&lt;p&gt;I haven&amp;rsquo;t used this one as often, but &lt;code&gt;##pattern&lt;/code&gt; removes the longest match of the &lt;em&gt;word&lt;/em&gt; from the beginning of the &lt;em&gt;parameter&lt;/em&gt;. I cooked up an example to count the occurrences of each file ending in the current directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f in *.*; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;f&lt;/span&gt;##*.&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt; | sort | uniq -c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s not especially robust (e.g., it would show &lt;code&gt;.tar.gz&lt;/code&gt; as simply &lt;code&gt;.gz&lt;/code&gt;), but this is an example of a lightweight and versatile script with just Bash builtins and standard commands. Knowing the tools you&amp;rsquo;re working with allows you to adapt them to your current situation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html&#34;&gt;https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;history-expansion&#34;&gt;History Expansion&lt;/h3&gt;
&lt;p&gt;Another type of expansion I use frequently is history expansion. The history expansion character is &lt;code&gt;!&lt;/code&gt;, and there are several useful ways to use history within Bash commands.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;!!&lt;/code&gt; repeats the most recent command. This is especially useful if you need to rerun a command with &lt;code&gt;sudo&lt;/code&gt;. I often find myself running &lt;code&gt;sudo !!&lt;/code&gt; after accidentally trying to install a program without superuser privileges.&lt;/p&gt;
&lt;p&gt;You can also expand any argument from the previous command using &lt;code&gt;!:n&lt;/code&gt;, where n is the argument from the previous command, numbered from 0. More often than this, I use the shorthand &lt;code&gt;!$&lt;/code&gt; which references the last argument from the previous command.&lt;/p&gt;
&lt;p&gt;For example, if you&amp;rsquo;ve just run &lt;code&gt;diff really\ long\ filename\ I\ really\ don\&#39;t\ want\ to\ type.txt other.txt&lt;/code&gt;, you can edit the first file by typing &lt;code&gt;vim !:1&lt;/code&gt;, without having to retype the long filename.&lt;/p&gt;
&lt;p&gt;You can also reference previous words in the current command using the &lt;code&gt;!#&lt;/code&gt; event designator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo words and more !#1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;words and more words&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;example-replacing-underscores-with-dashes-in-a-filename&#34;&gt;Example: Replacing underscores with dashes in a filename&lt;/h4&gt;
&lt;p&gt;Here&amp;rsquo;s how I solved the underscore/dash issue, as promised. I used the &lt;code&gt;s&lt;/code&gt; modifier to search and replace within the backreferenced word within the current command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv synthesized_beef_menu.md !#:1:gs/_/-
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv synthesized_beef_menu.md synthesized-beef-menu.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that this is real output; Bash prints the expanded command before showing the output.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;So simple! We just reference the second word (index &lt;code&gt;1&lt;/code&gt;) in the current command and globally subsitute &lt;code&gt;-&lt;/code&gt; for &lt;code&gt;_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice that history expansion works differently from the &lt;code&gt;${}&lt;/code&gt; parameter expansion notation we saw previously. Rather than using the delimiter as a command, in history expansion you can use one or more modifiers separatd by &lt;code&gt;:&lt;/code&gt; characters. If you have two files named &lt;code&gt;green-old.txt&lt;/code&gt; and &lt;code&gt;green-new&lt;/code&gt; (no file ending), you can make the second out of the first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat green-old.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat !:1:r:s/old/new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat green-new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This references word &lt;code&gt;1&lt;/code&gt; from the previous command, removes the filename extension, leaving the root filename, then replaces &amp;ldquo;old&amp;rdquo; with &amp;ldquo;new&amp;rdquo;. Not terribly useful for a single file, but this type of expansion could easily be used in a quick script to move a large number of files into a new format.&lt;/p&gt;
&lt;p&gt;To replace globally (not just once per line), you have to put the modifier &lt;em&gt;before&lt;/em&gt; the search/replace pattern: &lt;code&gt;!!:0:gs/pattern/replacement&lt;/code&gt;. This is different from sed-style search and replace flags, which go at the end after a terminal slash.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/History-Interaction.html&#34;&gt;https://www.gnu.org/software/bash/manual/html_node/History-Interaction.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;other-types-of-expansion&#34;&gt;Other types of expansion&lt;/h3&gt;
&lt;p&gt;I recommend looking through the &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html&#34;&gt;documentation&lt;/a&gt; for expansions and applying it to your own routines. A little goes a long way! If you get in the habit of noticing inefficiency and fixing it with the shell, you&amp;rsquo;ll find yourself finishing menial tasks quicker, leaving more time to spend solving problems that matter.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How to Analyze Application Logs and Extract Actionable Insights</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/02/how-to-analyze-application-logs-and-extract-actionable-insights/"/>
      <id>https://www.endpointdev.com/blog/2025/02/how-to-analyze-application-logs-and-extract-actionable-insights/</id>
      <published>2025-02-28T00:00:00+00:00</published>
      <author>
        <name>Edgar Mlowe</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/02/how-to-analyze-application-logs-and-extract-actionable-insights/logs.webp&#34; alt=&#34;A side-on view of a large pile of wooden logs&#34;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&#34;https://unsplash.com/@tcdinger&#34;&gt;Timo C. Dinger&lt;/a&gt; on &lt;a href=&#34;https://unsplash.com/photos/brown-and-black-wood-logs-Oo3L5fL1lBU&#34;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Logs often accumulate unnoticed—until something breaks. Then, they suddenly become vital tools for diagnosing issues. By combining just a few command-line techniques, you can quickly spot recurring problems, identify suspicious activity, and strengthen your application’s defenses.&lt;/p&gt;
&lt;p&gt;Below is a sample error log we’ll reference in the examples:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 12:34:56] [client 192.168.1.1:12345] PHP Notice: Undefined variable $foo in /var/www/html/index.php on line 45 | referer: http://example.com/index.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 12:34:56] [client 192.168.1.1:12345] PHP Notice: Undefined variable $foo in /var/www/html/index.php on line 45 | referer: http://example.com/index.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 12:34:57] [client 192.168.1.1:12345] PHP Notice: Undefined variable $foo in /var/www/html/index.php on line 45 | referer: http://example.com/index.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 12:35:00] [client 10.0.0.2:6789] PHP Warning: Division by zero in /var/www/html/script.php on line 23 | referer: http://example.com/script.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 13:35:01] [client 10.0.0.2:6789] PHP Warning: Division by zero in /var/www/html/script.php on line 23 | referer: http://example.com/script.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 13:36:10] [client 192.168.1.1:12345] PHP Fatal error: Call to undefined function baz() in /var/www/html/lib.php on line 78 | referer: http://example.com/index.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2025-01-01 14:36:11] [client 172.16.0.5:54321] PHP Fatal error: Call to undefined function baz() in /var/www/html/lib.php on line 78 | referer: http://example.com/index.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;a-note-on-commands&#34;&gt;A Note on Commands&lt;/h3&gt;
&lt;p&gt;Throughout this blog, you’ll notice repeated use of commands like &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt;, and &lt;code&gt;sort&lt;/code&gt;. These tools are indispensable for log analysis, allowing you to filter, transform, and summarize data efficiently. Here are some tips for learning these tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;man &amp;lt;command&amp;gt;&lt;/code&gt; (e.g., &lt;code&gt;man awk&lt;/code&gt;) to access the manual and dive deeper into a specific command&lt;/li&gt;
&lt;li&gt;Experiment with small examples to understand how commands like &lt;code&gt;awk&lt;/code&gt; process patterns or how &lt;code&gt;grep&lt;/code&gt; extracts data&lt;/li&gt;
&lt;li&gt;For a broader look at how these commands enhance productivity, check out my blog post: &lt;a href=&#34;/blog/2024/06/practical-linux-comandline-tips/&#34;&gt;Practical Linux Command Line Tips for Productivity and Efficiency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These commands are not just for log analysis—they’re powerful for any data manipulation task you encounter. With practice, they can become essential to your workflow.&lt;/p&gt;
&lt;h3 id=&#34;1-debugging-application-errors&#34;&gt;1. Debugging Application Errors&lt;/h3&gt;
&lt;h4 id=&#34;11-summarize-frequent-issues&#34;&gt;1.1 Summarize Frequent Issues&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sed -E &amp;#39;s/^\[.*\] //&amp;#39; error.log | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Remove timestamps/​client&amp;rsquo;s IP, then sort and count duplicates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: A quick snapshot of which errors appear most often&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 PHP Notice: Undefined variable $foo ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 PHP Warning: Division by zero ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 PHP Fatal error: Call to undefined function baz() ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;12-categorize-errors-by-type&#34;&gt;1.2 Categorize Errors by Type&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -oE &amp;#39;PHP [^:]+&amp;#39; error.log | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Extract error types (e.g., Notice, Warning, Fatal error)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Know whether notices, warnings, or fatal errors dominate&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 Notice
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 Warning
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 Fatal error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;13-find-problematic-scripts&#34;&gt;1.3 Find Problematic Scripts&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;awk -F&amp;#39;in &amp;#39; &amp;#39;{print $2}&amp;#39; error.log | awk &amp;#39;{print $1}&amp;#39; | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Identify which files generate the most errors&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Pinpoint error hotspots for focused debugging&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 /var/www/html/index.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 /var/www/html/script.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 /var/www/html/lib.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;2-monitoring-system-behavior&#34;&gt;2. Monitoring System Behavior&lt;/h3&gt;
&lt;h4 id=&#34;21-track-problematic-ips&#34;&gt;2.1 Track Problematic IPs&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;awk -F&amp;#39;\[client &amp;#39; &amp;#39;{print $2}&amp;#39; error.log | awk -F&amp;#39;:&amp;#39; &amp;#39;{print $1}&amp;#39; | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Count how many errors each IP triggers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Identify suspicious or high-traffic IPs&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4 192.168.1.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 10.0.0.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 172.16.0.5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;22-spot-high-error-time-periods&#34;&gt;2.2 Spot High-Error Time Periods&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;awk -F&amp;#39;[][]&amp;#39; &amp;#39;{split($2, time, &amp;#34;:&amp;#34;); print $1, time[1]&amp;#34;:&amp;#34;time[2]&amp;#34;:00&amp;#34;}&amp;#39; error.log | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Group errors by minute, revealing spikes or trends&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Correlate error surges with deployments or traffic peaks&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 2025-01-01 12:34:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 2025-01-01 14:36:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 2025-01-01 13:36:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;23-analyze-ipreferer-pairs&#34;&gt;2.3 Analyze IP–Referer Pairs&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep &amp;#34;referer:&amp;#34; error.log | awk -F&amp;#39;\\[client &amp;#39; &amp;#39;{print $2}&amp;#39; | awk -F&amp;#39;:| referer: &amp;#39; &amp;#39;{print $1, $3}&amp;#39; | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Match IP addresses with the URLs they refer from&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Detect repeat offenders or malicious traffic patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3 192.168.1.1 Undefined variable $foo ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 10.0.0.2 Division by zero ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 172.16.0.5 Call to undefined function baz() ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;3-enhancing-security&#34;&gt;3. Enhancing Security&lt;/h3&gt;
&lt;h4 id=&#34;31-watch-sensitive-urls&#34;&gt;3.1 Watch Sensitive URLs&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -E &amp;#34;admin|login&amp;#34; script_error_frequency.txt | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Flag frequent hits on admin or login pages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Gauge whether sensitive endpoints are under attack&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 /var/www/html/login.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 /var/www/html/admin.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;32-pinpoint-critical-times&#34;&gt;3.2 Pinpoint Critical Times&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -E &amp;#34;admin|login&amp;#34; error.log | awk -F&amp;#39;[][]&amp;#39; &amp;#39;{split($2, time, &amp;#34;:&amp;#34;); print $1, time[1]&amp;#34;:&amp;#34;time[2]&amp;#34;:00&amp;#34;}&amp;#39; | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Identify specific time windows for sensitive access&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Cross-reference suspicious activity with your security logs&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plaintext&#34; data-lang=&#34;plaintext&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 2025-01-01 12:34:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 2025-01-01 13:35:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1 2025-01-01 12:35:00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;These commands demonstrate how quickly you can glean insights from logs. With a little creativity, you can expand them to track response times, detect performance bottlenecks, and safeguard critical endpoints. Whether you’re tackling PHP errors or any other type of log data, the same principles apply: filter, sort, count, and investigate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Curious to learn more?&lt;/strong&gt; Combine these strategies with automation tools, integrate them into CI/CD pipelines, or hook them up to visual dashboards. Your logs will become a gold mine of actionable information.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Practical Linux Command Line Tips for Productivity and Efficiency</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2024/06/practical-linux-comandline-tips/"/>
      <id>https://www.endpointdev.com/blog/2024/06/practical-linux-comandline-tips/</id>
      <published>2024-06-22T00:00:00+00:00</published>
      <author>
        <name>Edgar Mlowe</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2024/06/practical-linux-comandline-tips/three-shadows.webp&#34; alt=&#34;A shadow draws sharp lines on brightly lit concrete. On the left side is a thick line descending across the full height diagonally, connected at the top to a subtly curved line which spans the full width of the image. It is connected by a thinner parallel diagonal line, which has two more horizontal lines equally spaced across the image.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2024. --&gt;
&lt;p&gt;Feeling stuck with basic Linux commands? You&amp;rsquo;re not alone! Many people know some commands but don&amp;rsquo;t feel efficient. The good news is that with some know-how and common commands, you can transform your skills.&lt;/p&gt;
&lt;p&gt;In this post, you&amp;rsquo;ll learn to combine commands with pipes, master shell techniques, efficiently recall and edit past commands, and navigate the filesystem with speed. Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;h3 id=&#34;1-combining-commands-with-pipes&#34;&gt;1. Combining Commands with Pipes&lt;/h3&gt;
&lt;h4 id=&#34;understanding-how-pipes-work&#34;&gt;Understanding How Pipes Work&lt;/h4&gt;
&lt;p&gt;Ever wish your commands could work together? Pipes make it happen! They let one command pass its output to another, creating a smooth workflow.&lt;/p&gt;
&lt;p&gt;Commands take input (&lt;code&gt;stdin&lt;/code&gt;) and give output (&lt;code&gt;stdout&lt;/code&gt;). The pipe symbol (&lt;code&gt;|&lt;/code&gt;) links them, making life easier.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;ls -l /bin&lt;/code&gt; lists files in the &lt;code&gt;/bin&lt;/code&gt; directory, but the amount of output is overwhelming. Try &lt;code&gt;ls -l /bin | less&lt;/code&gt; to view one screen at a time—like having a personal organizer! This command pipes the output of the &lt;code&gt;ls&lt;/code&gt; command into the pager &lt;code&gt;less&lt;/code&gt;, which is very useful for reading large amounts of data.&lt;/p&gt;
&lt;p&gt;Let’s dive into pipes and practice them with commands like &lt;code&gt;wc&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, and &lt;code&gt;uniq&lt;/code&gt; to handle data like a pro. If any of these commands are new to you, use &lt;code&gt;man&lt;/code&gt; (short for &amp;ldquo;manual&amp;rdquo;) followed by the command name to learn more. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;man grep&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;practical-examples-real-world-use-cases-for-combining-commands&#34;&gt;Practical Examples: Real-World Use Cases for Combining Commands&lt;/h4&gt;
&lt;h5 id=&#34;example-1-extracting-information-from-log-files&#34;&gt;Example 1: Extracting Information from Log Files&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Task&lt;/strong&gt;: Find all error messages in a log file and count them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample Data (&lt;code&gt;application.log&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INFO 2024-06-07 User login successful
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR 2024-06-07 Failed to connect to database
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INFO 2024-06-07 User logout
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR 2024-06-07 Timeout while retrieving data
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INFO 2024-06-07 Session expired
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ERROR 2024-06-07 Null pointer exception&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Command&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep &amp;#39;ERROR&amp;#39; application.log | wc -l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grep &#39;ERROR&#39; application.log&lt;/code&gt; searches for lines containing &amp;ldquo;ERROR&amp;rdquo; in &lt;code&gt;application.log&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The output is then passed to &lt;code&gt;wc -l&lt;/code&gt;, which counts the number of lines, giving you the total number of error messages. &lt;code&gt;wc&lt;/code&gt; is short for &amp;ldquo;word count&amp;rdquo;, while &lt;code&gt;-l&lt;/code&gt; stands for lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Expected Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h5 id=&#34;example-2-processing-xml-files-for-public-health-data&#34;&gt;Example 2: Processing XML Files for Public Health Data&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Task&lt;/strong&gt;: Extract all patient IDs from multiple XML files and sort them uniquely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample Data (&lt;code&gt;file1.xml&lt;/code&gt;, &lt;code&gt;file2.xml&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;file1.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patients&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patientId&amp;gt;&lt;/span&gt;123&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patientId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;John Doe&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patientId&amp;gt;&lt;/span&gt;124&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patientId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Jane Smith&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patients&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;file2.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patients&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patientId&amp;gt;&lt;/span&gt;124&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patientId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Jane Smith&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;patientId&amp;gt;&lt;/span&gt;125&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patientId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Mary Johnson&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patient&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/patients&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Command&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep &amp;#39;&amp;lt;patientId&amp;gt;&amp;#39; *.xml | cut -d &amp;#39;&amp;gt;&amp;#39; -f 2 | cut -d &amp;#39;&amp;lt;&amp;#39; -f 1 | sort | uniq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grep &#39;&amp;lt;patientId&amp;gt;&#39; *.xml&lt;/code&gt; searches for lines containing &lt;code&gt;&amp;lt;patientId&amp;gt;&lt;/code&gt; in all XML files.&lt;/li&gt;
&lt;li&gt;The output is then piped to &lt;code&gt;cut -d&#39;&amp;gt;&#39; -f2&lt;/code&gt; to extract the content after the &lt;code&gt;&amp;gt;&lt;/code&gt; character.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cut -d&#39;&amp;lt;&#39; -f1&lt;/code&gt; further extracts the content before the &lt;code&gt;&amp;lt;&lt;/code&gt; character.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sort&lt;/code&gt; sorts the IDs alphabetically.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uniq&lt;/code&gt; removes duplicate entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Expected Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;123
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;124
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;125&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h5 id=&#34;example-3-organizing-text-data-into-a-csv-file&#34;&gt;Example 3: Organizing Text Data into a CSV File&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Task&lt;/strong&gt;: Convert a space-separated file to a CSV file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sample Data (&lt;code&gt;data.txt&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name Age Location
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Alice 30 New_York
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Bob 25 Los_Angeles
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Charlie 35 Chicago&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Command&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat data.txt | tr &amp;#39; &amp;#39; &amp;#39;,&amp;#39; &amp;gt; data.csv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat data.txt&lt;/code&gt; reads the content of &lt;code&gt;data.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The output is then piped to &lt;code&gt;tr &#39; &#39; &#39;,&#39;&lt;/code&gt;, which translates spaces to commas.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; data.csv&lt;/code&gt; redirects the final output to &lt;code&gt;data.csv&lt;/code&gt;. We&amp;rsquo;ll cover redirection in more detail later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Expected Output (&lt;code&gt;data.csv&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name,Age,Location
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Alice,30,New_York
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Bob,25,Los_Angeles
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Charlie,35,Chicago&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These examples demonstrate how simple commands can be combined to achieve powerful and useful results. Experiment with these commands and modify them to fit your specific needs!&lt;/p&gt;
&lt;h3 id=&#34;2-mastering-shell-techniques&#34;&gt;2. Mastering Shell Techniques&lt;/h3&gt;
&lt;p&gt;The shell is the heart of your command line, acting as the bridge between you and the operating system. It does more than just run commands; it helps you manage and streamline your tasks efficiently. Let&amp;rsquo;s dive into some essential shell techniques.&lt;/p&gt;
&lt;h5 id=&#34;understanding-the-shell-with-ls&#34;&gt;Understanding the Shell with &lt;code&gt;ls&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;To get a clear picture of what the shell does versus what a command does, let&amp;rsquo;s look at the &lt;code&gt;ls&lt;/code&gt; command. When you run &lt;code&gt;ls&lt;/code&gt;, the shell and the command work together to get things done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shell&amp;rsquo;s Job&lt;/strong&gt;: The shell processes wildcards (like &lt;code&gt;*.py&lt;/code&gt;), sets up input and output redirections, and manages environment variables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command&amp;rsquo;s Job&lt;/strong&gt;: The &lt;code&gt;ls&lt;/code&gt; command lists directory contents.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: List all Python files in a directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls *.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;shell&lt;/strong&gt; expands &lt;code&gt;*.py&lt;/code&gt; to match all Python files (e.g., &lt;code&gt;data.py&lt;/code&gt;, &lt;code&gt;main.py&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;ls&lt;/code&gt; Command&lt;/strong&gt; receives the list of Python files and displays them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;1-pattern-matching-for-filenames&#34;&gt;1. Pattern Matching for Filenames&lt;/h5&gt;
&lt;p&gt;Pattern matching allows you to select multiple files with a single command using &lt;a href=&#34;https://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm&#34;&gt;wildcards&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: List all text files.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls *.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command lists all files ending with &lt;code&gt;.txt&lt;/code&gt;, like &lt;code&gt;report.txt&lt;/code&gt;, &lt;code&gt;notes.txt&lt;/code&gt;, and &lt;code&gt;summary.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: List all files that start with &amp;ldquo;data&amp;rdquo;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls data*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command lists all files starting with &amp;ldquo;data&amp;rdquo;, like &lt;code&gt;data1.csv&lt;/code&gt;, &lt;code&gt;data2.csv&lt;/code&gt;, and &lt;code&gt;database.db&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;: List all files that have numbers in their names.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls *[0-9]*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command lists files that contain any digit, like &lt;code&gt;file1.txt&lt;/code&gt;, &lt;code&gt;report2.doc&lt;/code&gt;, and &lt;code&gt;data2023.csv&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;2-variables-to-store-values&#34;&gt;2. Variables to Store Values&lt;/h5&gt;
&lt;p&gt;Variables let you store data that can be reused in your commands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: Create a variable to store your project directory path.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;PROJECT_DIR&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/home/user/myproject&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$PROJECT_DIR&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command sets the &lt;code&gt;PROJECT_DIR&lt;/code&gt; variable and then uses it to change to that directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: Store the result of a command in a variable.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;DATE&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;date +%Y-%m-%d&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Today&amp;#39;s date is &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$DATE&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command sets the &lt;code&gt;DATE&lt;/code&gt; variable to the current date using &lt;a href=&#34;https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html&#34;&gt;command substitution&lt;/a&gt; and then prints the contents of the &lt;code&gt;DATE&lt;/code&gt; variable.&lt;/p&gt;
&lt;h5 id=&#34;3-redirection-of-input-and-output&#34;&gt;3. Redirection of Input and Output&lt;/h5&gt;
&lt;p&gt;Redirection allows you to control where your command&amp;rsquo;s input and output go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: Save the output of a command to a file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls -l &amp;gt; filelist.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command lists all files in long format and saves the output to &lt;code&gt;filelist.txt&lt;/code&gt;. Redirection with the single right bracket will replace the contents of the target file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: Append the output of a command to a file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &amp;#34;New entry&amp;#34; &amp;gt;&amp;gt; filelist.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command adds &amp;ldquo;New entry&amp;rdquo; to the end of &lt;code&gt;filelist.txt&lt;/code&gt;. Redirection with two right brackets will append to the contents of the target file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;: Use a file as input for a command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sort &amp;lt; unsorted.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command sorts the contents of &lt;code&gt;unsorted.txt&lt;/code&gt; and displays the result. The single left bracket reads the contents of the file on the right (&lt;code&gt;unsorted.txt&lt;/code&gt; in this case) and uses them as input to the command on the left (&lt;code&gt;sort&lt;/code&gt; in this case).&lt;/p&gt;
&lt;h5 id=&#34;4-quoting-and-escaping-to-disable-shell-features&#34;&gt;4. Quoting and Escaping to Disable Shell Features&lt;/h5&gt;
&lt;p&gt;Quoting and escaping are used to handle special characters in your commands. Double quotes won&amp;rsquo;t expand wildcards or break the string on spaces, but will still expand variables and substitute commands with &lt;code&gt;$()&lt;/code&gt;. Content in single quotes isn&amp;rsquo;t processed by the shell at all; all characters are retained literally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: Search for a phrase with spaces in a file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep &amp;#34;my search phrase&amp;#34; file.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command searches for the exact phrase &amp;ldquo;my search phrase&amp;rdquo; in &lt;code&gt;file.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: Use a variable inside a double-quoted string.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;NAME&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello, &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$NAME&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command prints &amp;ldquo;Hello, Alice&amp;rdquo; using the &lt;code&gt;NAME&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;: Use single quotes to prevent variable expansion.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Hello, $NAME&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command prints &lt;code&gt;Hello, $NAME&lt;/code&gt; without expanding the variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 4&lt;/strong&gt;: Use backslashes to escape special characters in a double-quoted string.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;This path costs \$139: C:\\Windows\\System32&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command prints &lt;code&gt;This path costs $139: C:\Windows\System32&lt;/code&gt;. The dollar sign and backlashes must be escaped with a &lt;code&gt;\&lt;/code&gt; so that they aren&amp;rsquo;t treated as special characters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 5&lt;/strong&gt;: Include a literal double quote in a string.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;He said, \&amp;#34;Hello, World!\&amp;#34;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command prints &lt;code&gt;He said, &amp;quot;Hello, World!&amp;quot;&lt;/code&gt; by escaping the double quotes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 6:&lt;/strong&gt;: Include a literal single quote in a single-quoted string.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;What&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;s up?&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command prints &amp;ldquo;What&amp;rsquo;s up?&amp;rdquo; using a more complex escape sequence—first, you close the single-quote string, then without a space you add a literal single-quote character with &lt;code&gt;\&#39;&lt;/code&gt;, then you start a single-quoted string again. In bash, when there are no spaces between two strings, the strings will be joined together.&lt;/p&gt;
&lt;h5 id=&#34;5-the-search-path-for-locating-programs-to-run&#34;&gt;5. The Search Path for Locating Programs to Run&lt;/h5&gt;
&lt;p&gt;The shell uses the PATH variable to find programs to execute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: View your current PATH.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$PATH&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command displays the directories in your current PATH.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: Add a directory to your PATH temporarily.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;PATH&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$PATH&lt;/span&gt;:/home/user/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command adds &lt;code&gt;/home/user/bin&lt;/code&gt; to your PATH for the current session. It reads the PATH variable, then concatenates the string &amp;ldquo;:/home/user/bin&amp;rdquo; to the end, similarly to how we escaped a single quote.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;: Add a directory to your PATH permanently.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;export PATH=$PATH:/home/user/bin&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;source&lt;/span&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command appends the new PATH to your &lt;code&gt;.bashrc&lt;/code&gt; file (using redirection!). &lt;code&gt;.bashrc&lt;/code&gt; is run every time a new shell is started. &lt;code&gt;source&lt;/code&gt; reloads &lt;code&gt;.bashrc&lt;/code&gt; for the current shell, using the new PATH for the current session.&lt;/p&gt;
&lt;h5 id=&#34;6-saving-changes-to-your-shell-environment&#34;&gt;6. Saving Changes to Your Shell Environment&lt;/h5&gt;
&lt;p&gt;Save environment changes by adding them to your shell configuration file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;: Set an environment variable for the current session.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;EDITOR&lt;/span&gt;=nano&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command sets the default text editor to &lt;code&gt;nano&lt;/code&gt; for the current session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;: Make an environment variable permanent.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;export EDITOR=nano&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;source&lt;/span&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command sets the default text editor to &lt;code&gt;nano&lt;/code&gt; by adding it to your &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;: Create an alias for a command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;alias ll=&amp;#34;ls -l&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;source&lt;/span&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command creates an alias &lt;code&gt;ll&lt;/code&gt; for &lt;code&gt;ls -l&lt;/code&gt; and makes it permanent by adding it to your &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Mastering these shell techniques will boost your productivity and make your command line experience more enjoyable. Dive in and start practicing these essential commands!&lt;/p&gt;
&lt;h3 id=&#34;3-efficient-command-recall-and-editing&#34;&gt;3. Efficient Command Recall and Editing&lt;/h3&gt;
&lt;p&gt;Tired of retyping long commands or fixing typos from scratch? The shell&amp;rsquo;s got you covered with command history and command-line editing, designed to save you time and effort.&lt;/p&gt;
&lt;p&gt;Imagine you just ran a complex command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;md5sum *.jpg | cut -c 1-32 | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Need to run it again? No need to retype it. The shell keeps a history of every command you run, so you can quickly recall and rerun them. This feature, known as &lt;em&gt;command history&lt;/em&gt;, is a favorite among power users for speeding up their workflow and cutting down on repetitive typing.&lt;/p&gt;
&lt;p&gt;Accidentally typed &lt;code&gt;*.jg&lt;/code&gt; instead of &lt;code&gt;*.jpg&lt;/code&gt;?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;md5sum *.jg | cut -c 1-32 | sort | uniq -c | sort -nr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;No problem! Instead of starting over, just edit the command directly. The shell’s &lt;em&gt;command-line editing&lt;/em&gt; lets you fix typos on the fly, similar to using a text editor.&lt;/p&gt;
&lt;p&gt;In this section, you&amp;rsquo;ll discover how to leverage command history and command-line editing to enhance your efficiency and minimize errors.&lt;/p&gt;
&lt;h4 id=&#34;command-history&#34;&gt;Command History&lt;/h4&gt;
&lt;p&gt;The shell keeps a record of every command you execute, allowing you to recall and reuse them with ease.&lt;/p&gt;
&lt;h5 id=&#34;viewing-the-command-history&#34;&gt;Viewing the Command History&lt;/h5&gt;
&lt;p&gt;The &lt;code&gt;history&lt;/code&gt; command lists all previously executed commands in your shell session. Each command is assigned an ID number for easy reference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;history&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1000  cd $HOME/Music
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1001  ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1002  mv jazz.mp3 jazzy-song.mp3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1003  play jazzy-song.mp3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1481  cd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1482  firefox https://google.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1483  history&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To view the most recent commands, limit the output with a number.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;history&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1482  firefox https://google.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1483  history
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1484  history 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also filter the history to find specific commands by piping to &lt;code&gt;grep&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;history&lt;/span&gt; | grep &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;cd&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1000  cd $HOME/Music
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1092  cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1123  cd Finances
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1375  cd Checking
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1481  cd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h5 id=&#34;environment-variables-for-history&#34;&gt;Environment Variables for History&lt;/h5&gt;
&lt;p&gt;Environment variables control how your shell handles command history. Key variables include &lt;code&gt;HISTSIZE&lt;/code&gt;, &lt;code&gt;HISTFILESIZE&lt;/code&gt;, and &lt;code&gt;HISTCONTROL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HISTSIZE&lt;/strong&gt;: Determines the number of commands to remember in the current session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$HISTSIZE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To change the size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;HISTSIZE&lt;/span&gt;=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;HISTFILESIZE&lt;/strong&gt;: Sets the number of commands to save in the history file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$HISTFILESIZE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To change the file size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;HISTFILESIZE&lt;/span&gt;=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;HISTCONTROL&lt;/strong&gt;: Controls what commands are saved. Common values include &lt;code&gt;ignorespace&lt;/code&gt; (ignore commands starting with a space) and &lt;code&gt;ignoredups&lt;/code&gt; (ignore duplicate commands).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;HISTCONTROL&lt;/span&gt;=ignoredups&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To combine options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;HISTCONTROL&lt;/span&gt;=ignoredups:ignorespace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;HISTIGNORE&lt;/strong&gt;: Excludes specific commands from being saved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;HISTIGNORE&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ls:cd:pwd&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This setting prevents &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, and &lt;code&gt;pwd&lt;/code&gt; commands from being saved in the history.&lt;/p&gt;
&lt;p&gt;Note that you should add these &lt;code&gt;export&lt;/code&gt; commands to your &lt;code&gt;.bashrc&lt;/code&gt; for them to take effect outside the current shell.&lt;/p&gt;
&lt;h4 id=&#34;history-expansion&#34;&gt;History Expansion&lt;/h4&gt;
&lt;p&gt;History expansion is a powerful shell feature that lets you reuse and modify previous commands quickly. It uses special expressions, typically starting with an exclamation mark (&lt;code&gt;!&lt;/code&gt;), to reference commands from your history.&lt;/p&gt;
&lt;h5 id=&#34;basic-history-expansion&#34;&gt;Basic History Expansion&lt;/h5&gt;
&lt;p&gt;You can repeat the last command with &lt;code&gt;!!&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reruns &lt;code&gt;echo &amp;quot;Hello, World!&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;referencing-specific-commands&#34;&gt;Referencing Specific Commands&lt;/h5&gt;
&lt;p&gt;To repeat a specific command from your history, use its ID number.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!1002&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reruns the command with ID 1002 (&lt;code&gt;mv jazz.mp3 jazzy-song.mp3&lt;/code&gt; in our example).&lt;/p&gt;
&lt;h5 id=&#34;using-substring-matches&#34;&gt;Using Substring Matches&lt;/h5&gt;
&lt;p&gt;You can recall the most recent command that starts with a specific string.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!mv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reruns the most recent &lt;code&gt;mv&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;To recall a command containing a specific substring anywhere, use &lt;code&gt;!?string?&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!?cd?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reruns the most recent command containing &lt;code&gt;cd&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;modifying-previous-commands&#34;&gt;Modifying Previous Commands&lt;/h5&gt;
&lt;p&gt;You can also modify the previous command before running it. For instance, use &lt;code&gt;^old^new&lt;/code&gt; to replace the first occurrence of &lt;code&gt;old&lt;/code&gt; with &lt;code&gt;new&lt;/code&gt; in the last command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Hello, Alice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^Alice^Bob&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This changes &lt;code&gt;Alice&lt;/code&gt; to &lt;code&gt;Bob&lt;/code&gt;, rerunning the command as &lt;code&gt;echo &amp;quot;Hello, Bob&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;using--and-&#34;&gt;Using &lt;code&gt;!$&lt;/code&gt; and &lt;code&gt;!*&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;!$&lt;/code&gt; refers to the last argument of the previous command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ls /some/directory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; !$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This changes to &lt;code&gt;/some/directory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;!*&lt;/code&gt; refers to all arguments of the previous command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp file1.txt file2.txt /backup/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm !*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This removes both &lt;code&gt;file1.txt&lt;/code&gt; and &lt;code&gt;file2.txt&lt;/code&gt; from &lt;code&gt;/backup/&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&#34;safety-with-p&#34;&gt;Safety with &lt;code&gt;:p&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;To avoid mistakes, use &lt;code&gt;:p&lt;/code&gt; to print the command without executing it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!1002:p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This prints the command with ID 1002 without running it. You can then confirm it before rerunning it.&lt;/p&gt;
&lt;h4 id=&#34;command-line-editing&#34;&gt;Command-Line Editing&lt;/h4&gt;
&lt;p&gt;Command-line editing is essential for fixing mistakes, modifying commands, and creating new commands efficiently. Here are some key techniques to help you edit commands quickly and effectively.&lt;/p&gt;
&lt;h5 id=&#34;cursoring-within-a-command&#34;&gt;Cursoring Within a Command&lt;/h5&gt;
&lt;p&gt;Use the left and right arrow keys to move the cursor back and forth within a command line. This allows you to make changes without retyping the entire command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:
To correct a typo, press the left arrow key to move the cursor to the mistake, fix it, and then press Enter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Useful Keystrokes&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Left arrow&lt;/code&gt;: Move left by one character&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Right arrow&lt;/code&gt;: Move right by one character&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + left arrow&lt;/code&gt;: Move left by one word (on macOS, try &lt;code&gt;Option + left arrow&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + right arrow&lt;/code&gt;: Move right by one word (on macOS, try &lt;code&gt;Option + right arrow&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + a&lt;/code&gt;: Move to the beginning of the command line&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl + e&lt;/code&gt;: Move to the end of the command line&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;incremental-search&#34;&gt;Incremental Search&lt;/h5&gt;
&lt;p&gt;Press &lt;code&gt;Ctrl + r&lt;/code&gt; to initiate an incremental search through your command history. This lets you search for a previously run command without scrolling through the entire history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:
Press &lt;code&gt;Ctrl + r&lt;/code&gt; and start typing part of a previous command. The shell will display matching commands as you type. Press &lt;code&gt;Ctrl + r&lt;/code&gt; again to cycle through other matches. Once you find the command, press Enter to run it or use the arrow keys to edit it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Additional Tips&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To recall the most recent search string, press &lt;code&gt;Ctrl + r&lt;/code&gt; twice.&lt;/li&gt;
&lt;li&gt;To stop the search and continue editing the current command, press &lt;code&gt;Esc&lt;/code&gt;, &lt;code&gt;Ctrl + j&lt;/code&gt;, or any arrow key.&lt;/li&gt;
&lt;li&gt;To quit the search and clear the command line, press &lt;code&gt;Ctrl + g&lt;/code&gt; or &lt;code&gt;Ctrl + c&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By mastering these command-line editing techniques, you can save time, reduce errors, and improve your efficiency when working in the shell.&lt;/p&gt;
&lt;h3 id=&#34;4-navigating-the-filesystem-with-speed&#34;&gt;4. Navigating the Filesystem with Speed&lt;/h3&gt;
&lt;h4 id=&#34;efficient-directory-navigation&#34;&gt;Efficient Directory Navigation&lt;/h4&gt;
&lt;p&gt;Navigating the filesystem efficiently can significantly boost productivity. Here are some techniques:&lt;/p&gt;
&lt;h5 id=&#34;using-cd&#34;&gt;Using &lt;code&gt;cd&lt;/code&gt;&lt;/h5&gt;
&lt;p&gt;The &lt;code&gt;cd&lt;/code&gt; (change directory) command is fundamental for navigation. Here are some practical tips:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Jump to the Home Directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command takes you directly to your home directory, regardless of your current location in the filesystem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate Using Variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;/Work
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; ~/Work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Both &lt;code&gt;$HOME&lt;/code&gt; and &lt;code&gt;~&lt;/code&gt; are shortcuts to your home directory, making it easy to navigate to subdirectories within it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to Another User&amp;rsquo;s Home Directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; ~username&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;cdpath&#34;&gt;CDPATH&lt;/h5&gt;
&lt;p&gt;Set the CDPATH variable to define base directories for quick navigation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Setting CDPATH:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;CDPATH&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;:&lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;/Work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using CDPATH:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; Work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;organizing-your-home-directory&#34;&gt;Organizing Your Home Directory&lt;/h4&gt;
&lt;p&gt;A well-organized home directory structure can streamline your workflow.&lt;/p&gt;
&lt;h5 id=&#34;strategies-for-fast-navigation&#34;&gt;Strategies for Fast Navigation&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use Descriptive Names:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p &lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;/Projects/{Work,Personal,OpenSource}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create Aliases:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;work&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;cd &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/Projects/Work&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;personal&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;cd &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$HOME&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/Projects/Personal&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;using-pushd-and-popd-for-directory-management&#34;&gt;Using pushd and popd for Directory Management&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;pushd&lt;/code&gt; and &lt;code&gt;popd&lt;/code&gt; commands are used to manage a stack of directories, allowing for efficient navigation between them. Here&amp;rsquo;s how they work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pushd&lt;/code&gt;: Adds a directory to the stack and changes to that directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;popd&lt;/code&gt;: Removes the top directory from the stack and changes to the new top directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;basic-usage&#34;&gt;Basic Usage&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Pushing a Directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;pushd&lt;/span&gt; /path/to/directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command adds &lt;code&gt;/path/to/directory&lt;/code&gt; to the stack and changes the current directory to it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Popping a Directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;popd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command removes the top directory from the stack and changes the current directory to the new top directory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;example-workflow&#34;&gt;Example Workflow&lt;/h5&gt;
&lt;p&gt;Let&amp;rsquo;s say you start in your home directory (&lt;code&gt;~/&lt;/code&gt;) and execute the following commands:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Pushing Directories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;pushd&lt;/span&gt; /var/www/html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;pushd&lt;/span&gt; /etc/apache2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The stack now looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;~/           (top)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/etc/apache2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/var/www/html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Popping Directories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;popd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After this command, the stack looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;~/           (top)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/var/www/html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigating with Aliases:&lt;/p&gt;
&lt;p&gt;You can create aliases for &lt;code&gt;pushd&lt;/code&gt; and &lt;code&gt;popd&lt;/code&gt; to make navigation easier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pd&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;popd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;gd&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pushd&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can use &lt;code&gt;gd&lt;/code&gt; to push directories onto the stack and &lt;code&gt;pd&lt;/code&gt; to pop directories off the stack.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These techniques will help you navigate your filesystem efficiently, allowing you to focus more on your tasks and less on typing long paths.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Mastering the command line can transform your productivity and efficiency. We&amp;rsquo;ve covered combining commands with pipes, mastering shell techniques, recalling and editing commands efficiently, and navigating the filesystem with speed. Dive in, experiment, and watch your skills grow!&lt;/p&gt;
&lt;p&gt;For further reading, I highly recommend the book &lt;a href=&#34;https://www.oreilly.com/library/view/efficient-linux-at/9781098113391/&#34;&gt;&amp;ldquo;Efficient Linux at the Command Line&amp;rdquo;&lt;/a&gt;. It took my command-line skills to the next level and inspired many of the tips and tricks shared in this blog.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Consolidating Multiple SFTP Accounts Into One Master Account</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/consolidating-multiple-sftp-accounts/"/>
      <id>https://www.endpointdev.com/blog/2020/03/consolidating-multiple-sftp-accounts/</id>
      <published>2020-03-16T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2020/03/consolidating-multiple-sftp-accounts/image-0.jpg&#34; alt=&#34;merging roads&#34; /&gt;
&lt;p&gt;&lt;a href=&#34;https://unsplash.com/photos/kzSNNqqS3Qs&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@dmey503&#34;&gt;Dan Meyers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recently, a client implemented a data-intensive workflow to generate various reports and insights from a list of facilities as part of an EpiTrax installation. Because a significant portion of these files contain sensitive healthcare data, they needed to strictly comply with HIPAA. Optimally, facilities should be able to transfer files securely and exclusively to our server. One of the best methods of achieving this is to create individual SSH File Transfer Protocol (SFTP) accounts for each source.&lt;/p&gt;
&lt;h3 id=&#34;sftp-account&#34;&gt;SFTP account&lt;/h3&gt;
&lt;p&gt;Private SFTP accounts were established for each facility and the data was received at a designated path. At these individual points of contact, a third-party application picks up the data and processes further into the pipeline. The following demonstrates how SFTP accounts are developed and configured:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a user group for SFTP accounts:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ addgroup sftpusers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Configure the following settings in sshd_config (this enables an SFTP account and sets the default location as the home path):&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ vi /etc/ssh/sshd_config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# override default of no subsystems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Subsystem       sftp    internal-sftp...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Match Group sftpusers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ChrootDirectory /home/%u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AllowTCPForwarding no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    X11Forwarding no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ForceCommand internal-sftp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Restart SSH server to apply changes:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ systemctl restart ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Create an SFTP user account for a facility and place in a folder on the home path to receive data:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# set new user name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;sftpuser&lt;/span&gt;=the-new-username
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -g sftpusers -s /usr/sbin/nologin &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R root:root /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;mount-multiple-accounts-to-one-account&#34;&gt;Mount multiple accounts to one account&lt;/h3&gt;
&lt;p&gt;The goal here is to point the data from many facilities to one location, but using a single account and path for multiple sites’ data could result in a breach of security and/​or privacy. Mounting the receiving path of a facility’s data onto a single master account and then to a “mount point” with a unique facility name takes care of this issue. The process next consolidates files from individual paths on a master account in one place where the application picks up messages for further processing.&lt;/p&gt;
&lt;p&gt;The SFTP accounts and the master account should be attached to the same group. This will permit individual accounts to write on the master account-mounted path. In turn, the master account can read files from the same location. This location now has administrative rights for both the SFTP user the group. Group permission of the mounted folder is set to sftpgroup and user permission is set to the facility account.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# create master user account&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ adduser master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ passwd master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Add master user to sftpgroup group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -a -G sftpgroup master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;getent group sftpgroup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# MOUNT_PATH and sub folders&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/master/MOUNT_PATH/{Input,Pickup,Backup,Archive}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R master:master /home/master/MOUNT_PATH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We wrote a script to automate the process of creating an SFTP account, mounting it at the master account path, and adding fstab entries to save the mount in the case of a reboot. The script not only saves time, but also avoids human error when creating accounts for all facilities.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# ./create_sftp_account.sh sftpfacilityone FACILITY_ONE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;sftpuser&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;facility_name&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Create SFTP account and add to sftpgroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -g sftpusers -s /usr/sbin/nologin &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -a -G sftpgroup &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown root:root /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Create path specific to facility in master account Input folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;:sftpgroup /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Mount sftp account into master account and set permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mount --bind /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt; /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;:sftpgroup /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod &lt;span style=&#34;color:#369&#34;&gt;g&lt;/span&gt;=rwxs /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Add fstab entry to persist and mount on reboot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/home/master/MOUNT_PATH/Input/&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; /home/&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/INPUT_PATH none bind 0 0&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Created user &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; at &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; mount point successfully&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;files-at-one-location&#34;&gt;Files at one location&lt;/h3&gt;
&lt;p&gt;Now, data files from facilities are available at individual folders under MOUNT_PATH/Input on the master account. This enables third-party applications to pick up files in a straightforward way to proceed with further processing. It also helps our client access the files for review from the master account easily without navigating into each separate account.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Mounting multiple SFTP accounts onto one master account turns out to be an efficient and beneficial method of consolidating data. Both safe and secure, running separate SFTP accounts establishes an exclusive private link between facilities and servers. The master account has the unique ability to access files belonging to each facility in order to process the data further.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: In order to avoid broken mounts, check the status by using the command &lt;code&gt;mount -fav&lt;/code&gt;. Problems with mount configurations can cause broken mounts after rebooting the server.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Making sense of XML/JSON items in the shell</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/12/making-sense-of-xml-json-in-shell/"/>
      <id>https://www.endpointdev.com/blog/2019/12/making-sense-of-xml-json-in-shell/</id>
      <published>2019-12-31T00:00:00+00:00</published>
      <author>
        <name>Muhammad Najmi bin Ahmad Zabidi</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/12/making-sense-of-xml-json-in-shell/image-0.jpg&#34; alt=&#34;a shell&#34;&gt;&lt;/p&gt;
&lt;p&gt;Working as a system administrator means I have to spend quite some time during my work (and even during casual surfing) with the terminal. Sometimes I feel that certain information I want could just be fetched and parsed through the terminal, without having to use my mouse and point to the browser.&lt;/p&gt;
&lt;p&gt;Some of the websites I visit use XML and JSON, which we could parse with Bash scripting. Previously I wrote a Ruby script to call Nokogiri to parse the XML elements until I found a Bash tool that could do the same thing.&lt;/p&gt;
&lt;p&gt;These tools have already been around for quite a while—I’d just like to share what I did with them. The tools I used are &lt;code&gt;xmlstarlet&lt;/code&gt; for XML parsing and &lt;code&gt;jq&lt;/code&gt; for JSON.&lt;/p&gt;
&lt;h3 id=&#34;xml&#34;&gt;XML&lt;/h3&gt;
&lt;p&gt;I have the following XML elements, and I’ll save them to a file called data.xml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;rss&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;version=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;xmlns:dc=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;http://purl.org/dc/elements/1.1/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;xmlns:sy=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;http://purl.org/rss/1.0/modules/syndication/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;xmlns:admin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;http://webns.net/mvcb/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;xmlns:rdf=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;http://www.w3.org/1999/02/22-rdf-syntax-ns#&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;xmlns:content=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;http://purl.org/rss/1.0/modules/content/&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;channel&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;eSolat JAKIM : Waktu Solat Hari Ini&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;link&amp;gt;&lt;/span&gt;Gombak,Petaling,Sepang,Hulu Langat,Hulu Selangor,Rawang,S.Alam&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/link&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;Gombak,Petaling,Sepang,Hulu Langat,Hulu Selangor,Rawang,S.Alam&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;dc:language&amp;gt;&lt;/span&gt;ms&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/dc:language&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;dc:creator&amp;gt;&lt;/span&gt;www.e-solat.gov.my&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/dc:creator&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;dc:rights&amp;gt;&lt;/span&gt;Copyright JAKIM&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/dc:rights&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;dc:date&amp;gt;&lt;/span&gt;26-12-2019 00:37:31&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/dc:date&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;admin:generatorAgent&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rdf:resource=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;expressionengine&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Imsak&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;05:53:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Subuh&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;06:03:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Syuruk&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;07:14:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Zohor&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;13:16:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Asar&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;16:39:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Maghrib&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;19:13:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Isyak&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;description&amp;gt;&lt;/span&gt;20:28:00&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/channel&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/rss&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I’ll use xmlstarlet, together with a bunch of the related flags to parse these elements into something which is more eye-friendly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xmlstarlet sel -T -t -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;------------------------------&amp;#34;&lt;/span&gt; -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Area: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//channel&amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Date: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//channel&amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dc:date&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;------------------------------&amp;#34;&lt;/span&gt; -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -t -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//item&amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Time: &amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; -- &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Time: &amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  /path/to/data.xml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The output looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Area: Gombak,Petaling,Sepang,Hulu Langat,Hulu Selangor,Rawang,S.Alam
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date: 26-12-2019 00:37:31
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Imsak -- Time: 05:53:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Subuh -- Time: 06:03:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Syuruk -- Time: 07:14:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Zohor -- Time: 13:16:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Asar -- Time: 16:39:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Maghrib -- Time: 19:13:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time: Isyak -- Time: 20:28:00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I’ll put this in a Bash script, and call it xmlstarlet-time.sh.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;XMLPATH&lt;/span&gt;=/home/seth/data.xml
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [[ -z &lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; ]]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Put the location code&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$0&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; &amp;lt;location code&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; -n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lynx -source &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://www.e-solat.gov.my/index.php?r=esolatApi/xmlfeed&amp;amp;zon=&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$XMLPATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xmlstarlet sel -T -t -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;------------------------------&amp;#34;&lt;/span&gt; -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Area: &amp;#34;&lt;/span&gt; -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//channel&amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Date: &amp;#34;&lt;/span&gt; -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//channel&amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dc:date&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;------------------------------&amp;#34;&lt;/span&gt; -n &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  -t -m &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;//item&amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Time: &amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; -- &amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Time: &amp;#34;&lt;/span&gt; -v &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt; -n  &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#369&#34;&gt;$XMLPATH&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, after making it executable with &lt;code&gt;chmod +x xmlstarlet-time.sh&lt;/code&gt;, I can just run the script whenever I need the info. In my case, I would type &lt;code&gt;./xmlstarlet-time.sh SGR01&lt;/code&gt; in order to get the above information. I got the code (in my case) from the XML URL above. Your use case will likely be different.&lt;/p&gt;
&lt;h3 id=&#34;json&#34;&gt;JSON&lt;/h3&gt;
&lt;p&gt;Let’s say I want to grab the latest currency exchange, taking the base of USD from exchangeratesapi.io. I can use curl to get the data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;https://api.exchangeratesapi.io/api/latest?base=USD&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which will return:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;rates&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;CAD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.3160649819&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;HKD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;7.7879061372&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;ISK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;122.3826714801&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;PHP&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;50.8402527076&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;DKK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;6.7429602888&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;HUF&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;299.4223826715&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;CZK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23.0009025271&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;GBP&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.7719584838&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;RON&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4.3131768953&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;SEK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;9.4361913357&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;IDR&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;13985.0180505415&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;INR&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;71.2567689531&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;BRL&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4.0835740072&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;RUB&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;62.0877256318&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;HRK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;6.719765343&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;JPY&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;109.3772563177&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;THB&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30.155234657&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;CHF&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.9817689531&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;EUR&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.9025270758&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;MYR&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4.1364620939&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;BGN&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.7651624549&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;TRY&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5.9561371841&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;CNY&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;7.0074909747&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;NOK&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;8.94566787&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;NZD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.5086642599&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;ZAR&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;14.1935018051&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.0&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;MXN&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;18.9626353791&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;SGD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.3553249097&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;AUD&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.4457581227&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;ILS&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3.4714801444&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;KRW&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1162.1931407942&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;PLN&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3.8445848375&lt;/span&gt;},&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;base&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2019-12-24&amp;#34;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using jq, we can format the information more readably:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl -s &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;https://api.exchangeratesapi.io/api/latest?base=USD&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rates&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CAD&amp;#34;&lt;/span&gt;: 1.3160649819,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;HKD&amp;#34;&lt;/span&gt;: 7.7879061372,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ISK&amp;#34;&lt;/span&gt;: 122.3826714801,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;PHP&amp;#34;&lt;/span&gt;: 50.8402527076,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;DKK&amp;#34;&lt;/span&gt;: 6.7429602888,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;HUF&amp;#34;&lt;/span&gt;: 299.4223826715,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CZK&amp;#34;&lt;/span&gt;: 23.0009025271,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;GBP&amp;#34;&lt;/span&gt;: 0.7719584838,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;RON&amp;#34;&lt;/span&gt;: 4.3131768953,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;SEK&amp;#34;&lt;/span&gt;: 9.4361913357,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;IDR&amp;#34;&lt;/span&gt;: 13985.0180505415,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;INR&amp;#34;&lt;/span&gt;: 71.2567689531,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;BRL&amp;#34;&lt;/span&gt;: 4.0835740072,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;RUB&amp;#34;&lt;/span&gt;: 62.0877256318,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;HRK&amp;#34;&lt;/span&gt;: 6.719765343,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;JPY&amp;#34;&lt;/span&gt;: 109.3772563177,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;THB&amp;#34;&lt;/span&gt;: 30.155234657,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CHF&amp;#34;&lt;/span&gt;: 0.9817689531,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;EUR&amp;#34;&lt;/span&gt;: 0.9025270758,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;MYR&amp;#34;&lt;/span&gt;: 4.1364620939,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;BGN&amp;#34;&lt;/span&gt;: 1.7651624549,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;TRY&amp;#34;&lt;/span&gt;: 5.9561371841,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CNY&amp;#34;&lt;/span&gt;: 7.0074909747,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;NOK&amp;#34;&lt;/span&gt;: 8.94566787,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;NZD&amp;#34;&lt;/span&gt;: 1.5086642599,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ZAR&amp;#34;&lt;/span&gt;: 14.1935018051,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;MXN&amp;#34;&lt;/span&gt;: 18.9626353791,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;SGD&amp;#34;&lt;/span&gt;: 1.3553249097,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;AUD&amp;#34;&lt;/span&gt;: 1.4457581227,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ILS&amp;#34;&lt;/span&gt;: 3.4714801444,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;KRW&amp;#34;&lt;/span&gt;: 1162.1931407942,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;PLN&amp;#34;&lt;/span&gt;: 3.8445848375
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;base&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2019-12-24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, I can make use of the tool in my shell script.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash -l
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;RED&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;\033[0;31m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;YELLOW&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;\033[1;33m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;GREEN&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;\033[0;32m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;NC&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;\033[0m&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [ -z &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;which jq&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt; ]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;You need to install jq, a JSON parsing tool \n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;sourcemoney&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; | tr &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;[:lower:]&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;[:upper:]&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;target&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$3&lt;/span&gt; | tr &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;[:lower:]&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;[:upper:]&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;sumber&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;curl -s &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://api.exchangeratesapi.io/api/latest?base=&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sourcemoney&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; | jq . | grep -i &lt;span style=&#34;color:#369&#34;&gt;$target&lt;/span&gt; | awk -F &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;:|,&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;{ print $2 }&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;jumlah&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;%f*%f\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$sumber&lt;/span&gt; | bc&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Price per unit: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;GREEN&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;1 &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sourcemoney&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;NC&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; = &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;YELLOW&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$target&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; %.2f&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;NC&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$sumber&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; -e &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Source money: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;YELLOW&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sourcemoney&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;NC&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; -n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;printf&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Total money after the conversion: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;YELLOW&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$target&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; %.2f &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;NC&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$jumlah&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then I can save the script into a file called moneychanger-with-api.sh and make it executable with &lt;code&gt;chmod +x moneychanger-with-api.sh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And now the script will do the parsing for me, without the need for a browser.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./moneychanger-with-api.sh 100 usd eur
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Price per unit: 1 USD =  EUR 0.90
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Source money: USD 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total money after the conversion: EUR 90.25
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./moneychanger-with-api.sh 100 eur sgd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Price per unit: 1 EUR =  SGD 1.50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Source money: EUR 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total money after the conversion: SGD 150.17&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Shell Command Outputs Truncated in Python</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2018/04/shell-command-outputs-truncated-in-python/"/>
      <id>https://www.endpointdev.com/blog/2018/04/shell-command-outputs-truncated-in-python/</id>
      <published>2018-04-05T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2018/04/shell-command-outputs-truncated-in-python/programmers-reviewing-code-on-computer_925x.jpg&#34; alt=&#34;Two guys working at computers&#34; /&gt;&lt;br /&gt;
&lt;small&gt;&lt;a href=&#34;https://burst.shopify.com/photos/programmers-reviewing-code-on-computer&#34;&gt;Photo by Sarah Pflug of Burst&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Recently I was working on a Python script to do some parsing and processing on the output of shell commands in Ubuntu. The output that showed up was truncated.&lt;/p&gt;
&lt;p&gt;The below sections will walk through the debugging process to identify the root cause and implement a solution with detailed explanation, using Python 2.&lt;/p&gt;
&lt;h3 id=&#34;problem&#34;&gt;Problem&lt;/h3&gt;
&lt;p&gt;The following code block shows the output of a shell command which lists the installed packages, name and version, in Ubuntu.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# dpkg -l | grep ^ii | awk &amp;#39;{print $2 &amp;#34;    &amp;#34; $3}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;accountsservice    0.6.35-0ubuntu7.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;acl    2.2.52-1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser    3.113+nmu3ubuntu3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant    1.9.3-2build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant-optional    1.9.3-2build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-bin    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-data    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-utils    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apparmor    2.10.95-0ubuntu2.6~14.04.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The same shell command executes in the Python console but the output shows truncated values for a few packages’ versions, for example, accountsservice, adduser, apache2, etc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; installed_packages = subprocess.check_output([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dpkg -l | grep ^ii | awk &lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;{print $2 &amp;#34;    &amp;#34; $3}&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;], shell=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; installed_packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;accountsservice    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.6.35&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;ubuntu7.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;acl    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.2.52&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3.113&lt;/span&gt;+nmu3ubuntu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.9.3&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant-optional    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.9.3&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.4.7&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;ubuntu4&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-&lt;span style=&#34;color:#038&#34;&gt;bin&lt;/span&gt;    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.4.7&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;ubuntu4&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-data    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.4.7&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;ubuntu4&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-utils    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.4.7&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;ubuntu4&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apparmor    &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.10.95&lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;ubuntu2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;root-cause&#34;&gt;Root Cause&lt;/h3&gt;
&lt;p&gt;To identify the root cause of the problem, I started with source command &lt;code&gt;dpkg -l&lt;/code&gt; command without any filters and processing. I have noticed two different results for this command, with and without less command. The less command showed the complete result with scrolling as below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# dpkg -l | less&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;Desired&lt;/span&gt;=Unknown/Install/Remove/Purge/Hold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;color:#369&#34;&gt;Status&lt;/span&gt;=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|/ Err?=(none)/Reinst-required (Status,Err: &lt;span style=&#34;color:#369&#34;&gt;uppercase&lt;/span&gt;=bad)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;||/ Name                                  Version                                    Architecture Description
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++-=====================================-==========================================-============-===============================================================================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc  aacraid                               1.2.1-52011                                amd64        This driver supports Adaptec by PMC aacraid family of cards.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  accountsservice                       0.6.35-0ubuntu7.3                          amd64        query and manipulate user account information
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  acl                                   2.2.52-1                                   amd64        Access control list utilities
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  adduser                               3.113+nmu3ubuntu3                          all          add and remove users and groups
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  ant                                   1.9.3-2build1                              all          Java based build tool like make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  ant-optional                          1.9.3-2build1                              all          Java based build tool like make - optional libraries
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2                               2.4.7-1ubuntu4.18                          amd64        Apache HTTP Server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-bin                           2.4.7-1ubuntu4.18                          amd64        Apache HTTP Server (binary files and modules)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-data                          2.4.7-1ubuntu4.18                          all          Apache HTTP Server (common files)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-utils                         2.4.7-1ubuntu4.18                          amd64        Apache HTTP Server (utility programs &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; web servers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc  apache2.2-common                      2.2.22-1ubuntu1.11                         amd64        Apache HTTP Server common files
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apparmor                              2.10.95-0ubuntu2.6~14.04.1                 amd64        user-space parser utility &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; AppArmor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But &lt;code&gt;dpkg -l&lt;/code&gt; prints on the screen with truncated data due to the columns width constraint. The truncated values exactly match the Python console output. The output column width is decided by environment variable COLUMNS and commands restrict the column width in output based on COLUMNS value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# echo $COLUMNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;127&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# dpkg -l&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;Desired&lt;/span&gt;=Unknown/Install/Remove/Purge/Hold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| &lt;span style=&#34;color:#369&#34;&gt;Status&lt;/span&gt;=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|/ Err?=(none)/Reinst-required (Status,Err: &lt;span style=&#34;color:#369&#34;&gt;uppercase&lt;/span&gt;=bad)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;||/ Name                   Version          Architecture     Description
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++-======================-================-================-==================================================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc  aacraid                1.2.1-52011      amd64            This driver supports Adaptec by PMC aacraid family
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  accountsservice        0.6.35-0ubuntu7. amd64            query and manipulate user account information
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  acl                    2.2.52-1         amd64            Access control list utilities
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  adduser                3.113+nmu3ubuntu all              add and remove users and groups
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  ant                    1.9.3-2build1    all              Java based build tool like make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  ant-optional           1.9.3-2build1    all              Java based build tool like make - optional librari
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2                2.4.7-1ubuntu4.1 amd64            Apache HTTP Server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-bin            2.4.7-1ubuntu4.1 amd64            Apache HTTP Server (binary files and modules)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-data           2.4.7-1ubuntu4.1 all              Apache HTTP Server (common files)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apache2-utils          2.4.7-1ubuntu4.1 amd64            Apache HTTP Server (utility programs &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; web serve
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rc  apache2.2-common       2.2.22-1ubuntu1. amd64            Apache HTTP Server common files
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  apparmor               2.10.95-0ubuntu2 amd64            user-space parser utility &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; AppArmor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;solution&#34;&gt;Solution&lt;/h3&gt;
&lt;p&gt;The subprocess module of Python provides complete untruncated output of the shell command when the argument &lt;code&gt;env={}&lt;/code&gt; is passed to check_output function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; installed_packages = subprocess.check_output([&amp;#39;dpkg -l | grep ^ii | awk \&amp;#39;{print $2 &amp;#34;    &amp;#34; $3}\&amp;#39;&amp;#39;], shell=True, env={})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print installed_packages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;accountsservice    0.6.35-0ubuntu7.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;acl    2.2.52-1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adduser    3.113+nmu3ubuntu3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant    1.9.3-2build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ant-optional    1.9.3-2build1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-bin    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-data    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apache2-utils    2.4.7-1ubuntu4.18
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apparmor    2.10.95-0ubuntu2.6~14.04.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;explanation&#34;&gt;Explanation&lt;/h3&gt;
&lt;p&gt;Curious to know what is happening behind the scenes? The check_output function uses C library functions &lt;code&gt;execv&lt;/code&gt; or &lt;code&gt;execve&lt;/code&gt; for processing. It chooses the function based on the &lt;code&gt;env&lt;/code&gt; argument.&lt;/p&gt;
&lt;p&gt;Reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.python.org/2/library/subprocess.html&#34;&gt;subprocess documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/python/cpython/blob/master/Lib/subprocess.py&#34;&gt;subprocess.py source&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/google/python-subprocess32/blob/master/_posixsubprocess.c&#34;&gt;posixsubprocess.c source&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When no env argument is passed to &lt;code&gt;subprocess.check_output&lt;/code&gt;, the &lt;code&gt;os.execv&lt;/code&gt; function is called.&lt;/p&gt;
&lt;p&gt;When an env argument is passed to &lt;code&gt;subprocess.check_output&lt;/code&gt;, the &lt;code&gt;os.execve&lt;/code&gt; function is called.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; (i = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;; exec_array[i] != &lt;span style=&#34;color:#038&#34;&gt;NULL&lt;/span&gt;; ++i) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;char&lt;/span&gt; *executable = exec_array[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (envp) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;execve&lt;/span&gt;(executable, argv, envp);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;execv&lt;/span&gt;(executable, argv);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What makes the &lt;code&gt;execv&lt;/code&gt; and &lt;code&gt;execve&lt;/code&gt; functions produce different output?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;execv&lt;/code&gt; function passes through the shell COLUMNS variable which leads to truncating output columns to 127 width, like our reference system.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# echo $COLUMNS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;127
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print subprocess.check_output([&amp;#39;dpkg -l | grep libqtcore4&amp;#39;], shell=True)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  libqtcore4:amd64          4:4.8.5+git192-g0 amd64             Qt 4 core module
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print subprocess.check_output([&amp;#39;dpkg -l | grep libqtcore4&amp;#39;], shell=True, env={&amp;#39;COLUMNS&amp;#39;:&amp;#39;127&amp;#39;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  libqtcore4:amd64          4:4.8.5+git192-g0 amd64             Qt 4 core module&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;execve&lt;/code&gt; function uses additional argument environment variables and it is based on the &lt;code&gt;environ&lt;/code&gt; function. It uses environment variables available in env command which doesn&amp;rsquo;t have COLUMNS initialised. So output values returned without any column width restriction.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print subprocess.check_output([&amp;#39;dpkg -l | grep libqtcore4&amp;#39;], shell=True, env={})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  libqtcore4:amd64                      4:4.8.5+git192-g085f851+dfsg-2ubuntu4.1    amd64        Qt 4 core module
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print subprocess.check_output([&amp;#39;dpkg -l | grep libqtcore4&amp;#39;], shell=True, env={&amp;#39;COLUMNS&amp;#39;:&amp;#39;&amp;#39;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ii  libqtcore4:amd64                      4:4.8.5+git192-g085f851+dfsg-2ubuntu4.1    amd64        Qt 4 core module&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For more details refer to the man pages of &lt;code&gt;execv&lt;/code&gt;, &lt;code&gt;execve&lt;/code&gt;, &lt;code&gt;environ&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;It is always good to pass &lt;code&gt;env={}&lt;/code&gt; argument to &lt;code&gt;subprocess.check_output&lt;/code&gt; function whenever processing shell command output in Python. It helps avoid unstable results down the line due to truncated values.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How to check process duration in Linux with the “ps” command</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/08/how-to-check-process-duration-in-linux/"/>
      <id>https://www.endpointdev.com/blog/2017/08/how-to-check-process-duration-in-linux/</id>
      <published>2017-08-08T00:00:00+00:00</published>
      <author>
        <name>Muhammad Najmi bin Ahmad Zabidi</name>
      </author>
      <content type="html">
        &lt;p&gt;In certain cases we might want to get a certain process’ elapsed time for our own reason. Turns out “ps” command could easily assist us in that. According to “ps” manual, etime could put the duration of time in &lt;strong&gt;[[DD-]hh:]mm:ss. format&lt;/strong&gt;, while etimes in seconds.&lt;/p&gt;
&lt;p&gt;From “ps” manpage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etime       ELAPSED   elapsed &lt;span style=&#34;color:#038&#34;&gt;time&lt;/span&gt; since the process was started, in the form [[DD-]hh:]mm:ss.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etimes      ELAPSED   elapsed &lt;span style=&#34;color:#038&#34;&gt;time&lt;/span&gt; since the process was started, in seconds.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To use that, we could use (in [[DD-]hh:]mm:ss. format):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ps -p &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pid&amp;#34;&lt;/span&gt; -o etime&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or in seconds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ps -p &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pid&amp;#34;&lt;/span&gt; -o etimes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case the “pid” should be replaced with your intended process ID.&lt;/p&gt;
&lt;p&gt;The following will help to nicely reporting the output. We can put -o etime or -o etimes with other argument, that is “command”, in order to show the executed command along with its very own absolute path:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ps -p &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;28590&amp;#34;&lt;/span&gt; -o etime,command&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ELAPSED COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;21:45 /usr/bin/perl ./fastcgi-wrapper.pl &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;7999&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also get the start date of the process’ execution:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ ps -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;21745&lt;/span&gt; -o etime,command,start
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ELAPSED COMMAND                      STARTED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 1-19:47:45 /usr/lib/firefox/firefox      Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;02&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What if we do not want to manually parsing the PID, instead (since we are very sure) to just get the name of the running application? We could just simply use &lt;strong&gt;pgrep&lt;/strong&gt; or &lt;strong&gt;pidof&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ ps -p &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;pgrep firefox&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; -o pid,cmd,start,etime
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PID CMD                          STARTED     ELAPSED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;21745&lt;/span&gt; /usr/lib/firefox/firefox      Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;02&lt;/span&gt;  2-04:29:36&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ ps -p &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;pidof firefox&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; -o pid,cmd,start,etime
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  PID CMD                          STARTED     ELAPSED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;21745&lt;/span&gt; /usr/lib/firefox/firefox      Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;02&lt;/span&gt;  2-04:29:42&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What if the command issued many processes? Take an example of the Chrome browser:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ ps -p &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;pidof chrome&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; -o pid,comm,cmd,start,etime
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error: process ID list syntax error
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Usage:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ps [options]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Try &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;ps --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  or &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;ps --help &amp;lt;s|l|o|t|m|a&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; additional &lt;span style=&#34;color:#038&#34;&gt;help&lt;/span&gt; text.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;For more details see ps(1).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/s|l|o|t|m|a&amp;gt;&amp;lt;/simple|list|output|threads|misc|all&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The best way (so far) that I could get is by creating a loop. It seems &lt;strong&gt;pidof&lt;/strong&gt; is much more accurate when parsing the exact application (string) that we feed into it.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;pgrep&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;pgrep chrome&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt; ps -p &lt;span style=&#34;color:#369&#34;&gt;$i&lt;/span&gt; -o pid,comm,cmd,start,etime|tail -n +2;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2255&lt;/span&gt; chrome          /opt/google/chrome/chrome - 08:05:43    02:55:17
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4990&lt;/span&gt; chrome          /opt/google/chrome/chrome - 10:39:16       21:44
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5567&lt;/span&gt; chrome          /opt/google/chrome/chrome - 10:53:13       07:47
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;9448&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;31&lt;/span&gt;  3-12:25:08
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10033&lt;/span&gt; chrome          /opt/google/chrome/chrome     Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10044&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10050&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:42
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10187&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:39
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10234&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:37
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10236&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:43:37
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;19440&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:30:34    12:30:26
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20229&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-09:51:25
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20514&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:52:25    12:08:35
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20547&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:52:36    12:08:24
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;21009&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-09:27:11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22458&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-03:44:07
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22474&lt;/span&gt; chrome-gnome-sh /usr/bin/python3 /usr/bin/c   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-03:44:07
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23681&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-03:33:45
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23691&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-03:33:45
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23870&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:15:15    10:45:45
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;24544&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:40:17    10:20:43
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;25116&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:51:31    10:09:29
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;25466&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:59:55    10:01:05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;29060&lt;/span&gt; chrome          /opt/google/chrome/chrome - 02:15:42    08:45:18&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With &lt;strong&gt;pidof&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;najmi@ubuntu-ampang:~$ &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; i in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;pidof chrome&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt; ps -p &lt;span style=&#34;color:#369&#34;&gt;$i&lt;/span&gt; -o pid,comm,cmd,start,etime|tail -n +2;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;29060&lt;/span&gt; chrome          /opt/google/chrome/chrome - 02:15:42    08:47:40
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;25466&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:59:55    10:03:27
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;25116&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:51:31    10:11:51
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;24544&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:40:17    10:23:05
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23870&lt;/span&gt; chrome          /opt/google/chrome/chrome - 00:15:15    10:48:07
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23691&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-03:36:07
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;23681&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-03:36:07
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22458&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-03:46:29
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;21009&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-09:29:33
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20547&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:52:36    12:10:46
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20514&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:52:25    12:10:57
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20229&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Aug &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;03&lt;/span&gt;  1-09:53:47
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;19440&lt;/span&gt; chrome          /opt/google/chrome/chrome - 22:30:34    12:32:48
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10236&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:45:59
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10234&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:45:59
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10187&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:46:01
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10050&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:46:04
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10044&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:46:04
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10033&lt;/span&gt; chrome          /opt/google/chrome/chrome     Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;27&lt;/span&gt;  8-10:46:04
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;9448&lt;/span&gt; chrome          /opt/google/chrome/chrome -   Jul &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;31&lt;/span&gt;  3-12:27:30
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5567&lt;/span&gt; chrome          /opt/google/chrome/chrome - 10:53:13       10:09
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4990&lt;/span&gt; chrome          /opt/google/chrome/chrome - 10:39:16       24:06
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2255&lt;/span&gt; chrome          /opt/google/chrome/chrome - 08:05:43    02:57:39&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is other tool, called as &lt;strong&gt;stat&lt;/strong&gt; which records the timestamp of a file but for slightly different purpose. Stay tuned for the next blogpost!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Age comparison in Bash for files and processes</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/05/age-comparison-in-bash-for-files-and/"/>
      <id>https://www.endpointdev.com/blog/2017/05/age-comparison-in-bash-for-files-and/</id>
      <published>2017-05-22T00:00:00+00:00</published>
      <author>
        <name>Kiel Christofferson</name>
      </author>
      <content type="html">
        &lt;p&gt;You want your script to run a command only if elapsed-time for a given process is greater than &lt;em&gt;X&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Well, bash does &lt;em&gt;not&lt;/em&gt; inherently understand a time comparison like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [ 01:23:45 -gt 00:05:00 ]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, bash &lt;em&gt;can&lt;/em&gt; compare timestamps of files using -ot and -nt for “older than” and “newer than”, respectively. If the launch of our process includes creation of a PID file, then we are in luck! At the beginning of our loop, we can create a file with a specific age and use that for quick and simple comparison.&lt;/p&gt;
&lt;p&gt;For example, if we only want to take action when the process we care about was launched longer than 24 hours ago, try:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;touch -t &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;date --date=yesterday +%Y%m%d%H%M.%S&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$STAMPFILE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, within your script loop, compare the PID file with the $STAMPFILE, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [ &lt;span style=&#34;color:#369&#34;&gt;$PIDFILE&lt;/span&gt; -ot &lt;span style=&#34;color:#369&#34;&gt;$STAMPFILE&lt;/span&gt; ]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And of course if you want to be sure you’re working with the PID file of a process which is actually responding, you can try to send it signal 0 to check:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;kill&lt;/span&gt; -0 &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;cat &lt;span style=&#34;color:#369&#34;&gt;$PIDFILE&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Shell efficiency: mkdir and mv</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/03/shell-efficiency-mkdir-and-mv/"/>
      <id>https://www.endpointdev.com/blog/2017/03/shell-efficiency-mkdir-and-mv/</id>
      <published>2017-03-10T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;Little tools can be a nice improvement. Not everything needs to be thought-leaderish.&lt;/p&gt;
&lt;p&gt;For example, once upon a time in my Unix infancy I didn’t know that &lt;code&gt;mkdir&lt;/code&gt; has the &lt;code&gt;-p&lt;/code&gt; option to make intervening directories automatically. So back then, in order to create the path a/b/c/ I would’ve run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir a; mkdir a/b; mkdir a/b/c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;when I could instead have simply run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p a/b/c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In working at the shell, particularly on my own local machine, I often find myself wanting to move one or several files into a different location, to file them away. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv -i ~/Downloads/Some&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Long&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;File&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Name.pdf ~/some-other-long-file-name.tar.xz ~/archive/new...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;at which point I realize that the subdirectory of ~/archive that I want to move those files into does not yet exist.&lt;/p&gt;
&lt;p&gt;I can’t simply move to the beginning of the line and change &lt;code&gt;mv&lt;/code&gt; to &lt;code&gt;mkdir -p&lt;/code&gt; without removing my partially-typed &lt;code&gt;~/archive/new...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I can go ahead and remove that, and then after I run the command I have to change the &lt;code&gt;mkdir&lt;/code&gt; back to &lt;code&gt;mv&lt;/code&gt; and add back the &lt;code&gt;~/archive/new...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In one single day I found I was doing that so often that it became tedious, so I re-read the GNU coreutils manpage for mv to see if there was a relevant option I had missed or a new one that would help. And I searched the web to see if a prebuilt tool is out there, or if anyone had any nice solutions.&lt;/p&gt;
&lt;p&gt;To my surprise I found nothing suitable, but I did find some discussion forums full of various suggestions and many brushoffs and ill-conceived suggestions that either didn’t work for me or seemed much overengineered.&lt;/p&gt;
&lt;p&gt;The solution I came up with was very simple. I’ve been using it for a few months and am happy enough with it to share it and see if it helps anyone else.&lt;/p&gt;
&lt;p&gt;In zsh (my main local shell) add to ~/.zshrc:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkmv() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkdir -p -- &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$argv&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;[-1]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mv &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$@&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And in bash (which I use on most of the many servers I access remotely) add to ~/.bashrc:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkmv() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkdir -p -- &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;!#&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mv &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$@&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To use: Once you realize you’re about to try to move files or directories into a nonexistent directory, simply go to the beginning of the line (^A = control-A in standard emacs keybindings) and type &lt;code&gt;mk&lt;/code&gt; in front of the &lt;code&gt;mv&lt;/code&gt; that was already there:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkmv -i ~/Downloads/Some&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Long&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;File&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Name.pdf ~/some-other-long-file-name.tar.xz ~/archive/new...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It creates the directory (or directories) and then completes the move.&lt;/p&gt;
&lt;p&gt;There are a few important considerations that I didn’t foresee in my initial naive implementation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Having the name be &lt;em&gt;something&lt;/em&gt;mv meant less typing than something requiring me to remove the mv.&lt;/li&gt;
&lt;li&gt;For me, it needs to support not just moving one thing to one destination, but rather a whole list of things. That meant accessing the last argument (the destination) for the mkdir.&lt;/li&gt;
&lt;li&gt;I also needed to allow through arguments to &lt;code&gt;mv&lt;/code&gt; such as &lt;code&gt;-i&lt;/code&gt;, &lt;code&gt;-v&lt;/code&gt;, and &lt;code&gt;-n&lt;/code&gt;, which I often use.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;--&lt;/code&gt; argument to mkdir ensures that we don’t accidentally end up with any other options and that we can handle a destination with a leading &lt;code&gt;-&lt;/code&gt; (which does occasionally come up).&lt;/li&gt;
&lt;li&gt;The mv command needs to have a double-quoted &lt;code&gt;&amp;quot;$@&amp;quot;&lt;/code&gt; so that the original parameters are each expanded into double-quoted arguments, allowing for spaces and other shell metacharacters in the paths. (See the zsh and bash manpages for details on the important difference in behavior of &lt;code&gt;&amp;quot;$@&amp;quot;&lt;/code&gt; compared to &lt;code&gt;&amp;quot;$*&amp;quot;&lt;/code&gt; and either of them unquoted.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn’t support GNU extensions to mv such as the option &lt;code&gt;--target-directory&lt;/code&gt; that precedes the source paths. I don’t use that interactively, so I don’t mind.&lt;/p&gt;
&lt;p&gt;Because this is such a small thing, I avoided for years bothering to set it up. But now that I use it all the time, I’m glad I have it!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Using Awk to beautify grep searches</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/01/using-awk-to-beautify-grep-searches/"/>
      <id>https://www.endpointdev.com/blog/2017/01/using-awk-to-beautify-grep-searches/</id>
      <published>2017-01-18T00:00:00+00:00</published>
      <author>
        <name>Kamil Ciemniewski</name>
      </author>
      <content type="html">
        &lt;p&gt;Recently we’ve seen a sprout of re-implementations of many popular Unix tools. With the expansion of communities built around new languages or platforms, it seems that apart from the novelties in technologies—​the ideas on how to use them stay the same. There are more and more solutions to the same kinds of problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;text editors&lt;/li&gt;
&lt;li&gt;CSS pre-processors&lt;/li&gt;
&lt;li&gt;find-in-files tools&lt;/li&gt;
&lt;li&gt;screen scraping tools&lt;/li&gt;
&lt;li&gt;&amp;hellip; many more &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post I’d like to tackle the problem from yet another perspective. Instead of resolving to “new and cool” libraries and languages (grep implemented in X language)—​I’d like to use what’s out there already in terms of tooling to build a nice search-in-files tool for myself.&lt;/p&gt;
&lt;h3 id=&#34;search-in-files-tools&#34;&gt;Search in files tools&lt;/h3&gt;
&lt;p&gt;It seems that for many people it’s very important to have a “search in files” tool that they really like. Some of the nice work we’ve seen so far include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/petdance/ack2&#34;&gt;ack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/BurntSushi/ripgrep&#34;&gt;ripgrep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ggreer/the_silver_searcher&#34;&gt;the_silver_searcher&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are certainly very nice. As the goal of this post is to build something out of the tooling found in any minimal Unix-like installation—​they won’t work though. They either need to be compiled or require Perl to be installed which isn’t everywhere (e. g. FreeBSD on default—​though obviously available via the ports).&lt;/p&gt;
&lt;h3 id=&#34;what-i-really-need-from-the-tool&#34;&gt;What I really need from the tool&lt;/h3&gt;
&lt;p&gt;I do understand that for some developers, waiting 100 ms longer for the search results might be too long. I’m not like that though. Personally, all I care about when searching is how the results are being presented. I also like to have the consistency of using the same approach between many machines I work on. We’re often working on remote machines at End Point. The need to install e.g Rust compiler just to get the ripgrep tool is too time consuming and hence doesn’t contribute to getting things done faster. Same goes for e. g the_silver_searcher which needs to be compiled too. What options do I have then?&lt;/p&gt;
&lt;h3 id=&#34;using-good-old-unix-tools&#34;&gt;Using good old Unix tools&lt;/h3&gt;
&lt;p&gt;The “find in files” functionality is covered fully by the Unix grep tool. It allows searching for a given substring but also “Regex” matches. The output can not only contain only the lines with matches, but also the lines before and after to give some context. The tool can provide line numbers and also search recursively within directories.&lt;/p&gt;
&lt;p&gt;While I’m not into speeding it up, I’d certainly love to play with its output because I do care about my brain’s ability to parse text and hence: be more productive.&lt;/p&gt;
&lt;p&gt;The usual output of grep:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#888&#34;&gt;# searching inside of the ripgrep repo sources:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ egrep -nR Option src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:46:    fn cause(&amp;amp;self) -&amp;gt; Option&amp;lt;&amp;amp;StdError&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:64:    opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:71:    line_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:78:/// Options &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; configuring search.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:80:pub struct Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:89:    pub max_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:94:impl Default &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:95:    fn default() -&amp;gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:96:        Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:113:impl Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:160:            opts: Options::default(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:236:    pub fn max_count(mut self, count: Option&amp;lt;u64&amp;gt;) -&amp;gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:674:    pub fn next(&amp;amp;mut self, buf: &amp;amp;[u8]) -&amp;gt; Option&amp;lt;(usize, usize)&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:24:    opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:28:struct Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:38:    max_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:44:impl Default &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:45:    fn default() -&amp;gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:46:        Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:72:            opts: Options::default(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:148:    pub fn max_count(mut self, count: Option&amp;lt;u64&amp;gt;) -&amp;gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:186:    opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What my eyes would like to see is more like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mygrep Option src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/search_stream.rs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;46&lt;/span&gt;        fn cause(&amp;amp;self) -&amp;gt; Option&amp;lt;&amp;amp;StdError&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;64&lt;/span&gt;        opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;71&lt;/span&gt;        line_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;78&lt;/span&gt;    /// Options &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; configuring search.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;80&lt;/span&gt;    pub struct Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;89&lt;/span&gt;        pub max_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;94&lt;/span&gt;    impl Default &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;95&lt;/span&gt;        fn default() -&amp;gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;96&lt;/span&gt;            Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;113&lt;/span&gt;   impl Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;160&lt;/span&gt;               opts: Options::default(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;236&lt;/span&gt;       pub fn max_count(mut self, count: Option&amp;lt;u64&amp;gt;) -&amp;gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;674&lt;/span&gt;       pub fn next(&amp;amp;mut self, buf: &amp;amp;[u8]) -&amp;gt; Option&amp;lt;(usize, usize)&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/worker.rs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;24&lt;/span&gt;        opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;28&lt;/span&gt;    struct Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;38&lt;/span&gt;        max_count: Option&amp;lt;u64&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;44&lt;/span&gt;    impl Default &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;45&lt;/span&gt;        fn default() -&amp;gt; Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;46&lt;/span&gt;            Options {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;72&lt;/span&gt;                opts: Options::default(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;148&lt;/span&gt;       pub fn max_count(mut self, count: Option&amp;lt;u64&amp;gt;) -&amp;gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ⁞
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;186&lt;/span&gt;       opts: Options,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Fortunately, even the tiniest of Unix like system installation already has all we need to make it happen without the need to install anything else. Let’s take a look at how we can modify the output of grep with awk to achieve what we need.&lt;/p&gt;
&lt;h3 id=&#34;piping-into-awk&#34;&gt;Piping into awk&lt;/h3&gt;
&lt;p&gt;Awk has been in Unix systems for many years—​it’s older than me! It is a programming language interpreter designed specifically to work with text. In Unix, we can use pipes to direct output of one program to be the standard input of another in the following way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ oneapp | secondapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The idea with our searching tool is to use what we already have and pipe it between the programs to format the output as we’d like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ egrep -nR Option src | awk -f script.awk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that we used egrep when in this simple case we didn’t need to. It was sufficient to use fgrep or just grep.&lt;/p&gt;
&lt;h3 id=&#34;very-quick-introduction-to-coding-with-awk&#34;&gt;Very quick introduction to coding with Awk&lt;/h3&gt;
&lt;p&gt;Awk is one of the forefathers of languages like Perl and Ruby. In fact some of the ideas I’ll show you here exist in them as well.&lt;/p&gt;
&lt;p&gt;The structure of awk programs can be summarized as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# init code goes here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# &amp;#34;body&amp;#34; of the script follows:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/pattern-1/&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# what to do with the line matching the pattern?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/pattern-n/&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;END&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# finalizing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The interpreter provides default versions for all three parts: a &amp;ldquo;no-op&amp;rdquo; for BEGIN and END and &amp;ldquo;print each line unmodified&amp;rdquo; for the &amp;ldquo;body&amp;rdquo; of the script.&lt;/p&gt;
&lt;p&gt;Each line is being exploded into columns based on the &amp;ldquo;separator&amp;rdquo; which by default is any number of consecutive white characters. One can change it via the -F switch or by assigning the FS variable inside the BEGIN area. We’ll do just that in our example.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;columns&amp;rdquo; that lines are being exploded into can be accessed via the special variables:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$0&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;# the whole line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;# first column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; &lt;span style=&#34;color:#888&#34;&gt;# second column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# etc&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The FS variable can contain a pattern too. So for example if we’d have a file with the following contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;One | Two | Three | Four
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Eins | Zwei | Drei | Vier
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;One | Zwei | Three | Vier&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The following assignment would make Awk explode lines into proper columns:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  FS=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;|&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# the ~ operator gives true if left side matches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# the regex denoted by the right side:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; ~ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;One&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Running the following script would result with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file.txt | awk -f script.awk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Two
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Zwei&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;simple-awk-coding-to-format-the-search-results&#34;&gt;Simple Awk coding to format the search results&lt;/h3&gt;
&lt;p&gt;Armed with this simple knowledge, we can tackle the problem we stated in the earlier part of this post:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# the output of grep in the simple case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# contains:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# &amp;lt;file-name&amp;gt;:&amp;lt;line-number&amp;gt;:&amp;lt;file-fragment&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# let&amp;#39;s capture these parts into columns:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  FS=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# we are going to need to &amp;#34;remember&amp;#34; if the &amp;lt;file-name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# changes to print it&amp;#39;s name and to do that only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# once per file:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  file=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# we&amp;#39;ll be printing line numbers too; the non-consecutive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# ones will be marked with the special line with vertical&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# dots; let&amp;#39;s have a variable to keep track of the last&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# line number:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ln=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# we also need to know we&amp;#39;ve just encountered a new file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# not to print these vertical dots in such case:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  filestarted=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# let&amp;#39;s process every line except the ones grep prints to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# say if some binary file matched the predicate:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;!&lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/(--|Binary)/&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# remember: $1 is the first column which in our case is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# the &amp;lt;file-name&amp;gt; part; The file variable is used to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# store the file name recently processed; if the ones&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# don&amp;#39;t match up - then we know we encountered a new&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# file name:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; != file &amp;amp;&amp;amp; &lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; != &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    file=&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ln = &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    filestarted=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# if the line number isn&amp;#39;t greater than the last one by&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# one then we&amp;#39;re dealing with the result from non-consecutive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# line; let&amp;#39;s mark it with vertical dots:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; &amp;gt; ln + &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &amp;amp;&amp;amp; filestarted != &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;⁞&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# the substr function returns a substring of a given one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# starting at a given index; we need to print out the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# search result found in a file; here&amp;#39;s a gotcha: the results&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# may contain the &amp;#39;:&amp;#39; character as well! simply printing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# $3 could potentially left out some portions of it;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# this is why we&amp;#39;re using the whole line, cutting off the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# part we know for sure we don&amp;#39;t need:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  out=&lt;span style=&#34;color:#038&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$0&lt;/span&gt;, &lt;span style=&#34;color:#038&#34;&gt;length&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# let&amp;#39;s deal with only the lines that make sense:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; &amp;gt;= ln &amp;amp;&amp;amp; &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt; != &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# sprintf function matches the one found in C lang;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# here we&amp;#39;re making sure the line numbers are properly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# spaced:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    linum=&lt;span style=&#34;color:#038&#34;&gt;sprintf&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;%-4s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# print &amp;lt;line-number&amp;gt; &amp;lt;found-string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; linum &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; out
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# assign last line number for later use&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ln=&lt;span style=&#34;color:#369&#34;&gt;$2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# ensure that we know that we &amp;#34;started&amp;#34; current file:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    filestarted=&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that the “middle” part of the script (the one with the patterns and actions) gets ran in an implicit loop - once for each input line.&lt;/p&gt;
&lt;p&gt;To use the above awk script you could wrap it up with the following shell script:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;egrep -nR &lt;span style=&#34;color:#369&#34;&gt;$@&lt;/span&gt; | awk -f script.awk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we’re very trivially (and somewhat naively) passing all the arguments passed to the script to egrep with the use of $@.&lt;/p&gt;
&lt;p&gt;This of course is a simple solution. Some care needs to be applied when trying to make it work with A, B and C switches, it’s not difficult either though. All it takes is to e.g pipe it through sed (another great Unix tool - the “stream editor”) to replace the initial &amp;lsquo;-&amp;rsquo; characters in the [filename]-[line-number] parts to match our assumptions of having “:“ as the separator in the awk script.&lt;/p&gt;
&lt;h3 id=&#34;in-praise-of-what-already-works&#34;&gt;In praise of “what-already-works”&lt;/h3&gt;
&lt;p&gt;The simple script like shown above could easily be placed in your GitHub, BitBucket or GitLab account and fetched with curl on whichever machine you’re working on. With one call to curl and maybe another one to put the scripts somewhere in the local PATH you’d gain a productivity enhancing tool that doesn’t require anything else to work than what you already have.&lt;/p&gt;
&lt;p&gt;I’ll keep learning “what we already have” to not fall too much into “what’s hot and new” unnecessarily.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Bash: loop over a list of (possibly non-existing) files using wildcards with nullglob (or failglob) option</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/12/bash-loop-wildcards-nullglob-failglob/"/>
      <id>https://www.endpointdev.com/blog/2016/12/bash-loop-wildcards-nullglob-failglob/</id>
      <published>2016-12-12T00:00:00+00:00</published>
      <author>
        <name>Marco Matarazzo</name>
      </author>
      <content type="html">
        &lt;p&gt;Let’s say you’re working in &lt;strong&gt;Bash&lt;/strong&gt;, and you want to loop over a list of files, using wildcards.&lt;/p&gt;
&lt;p&gt;The basic code is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f in /path/to/files/*; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Found file: &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$f&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Easy as that. However, there could be a problem with this code: if the wildcard does not expand to actual files (i.e. there’s no file under /path/to/files/ directory), $f will expand to the path string itself, and the &lt;strong&gt;for&lt;/strong&gt; loop will still be executed one time with $f containing “/path/to/files/*”.&lt;/p&gt;
&lt;p&gt;How to prevent this from happening? &lt;strong&gt;Nullglob&lt;/strong&gt; is what you’re looking for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nullglob&lt;/strong&gt;, quoting &lt;a href=&#34;http://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html&#34;&gt;shopts man page&lt;/a&gt;, “allows filename patterns which match no files to expand to a null string, rather than themselves”.&lt;/p&gt;
&lt;p&gt;Using &lt;strong&gt;shopt -s&lt;/strong&gt; you can enable BASH optional behaviors, like &lt;strong&gt;Nullglob&lt;/strong&gt;. Here’s the final code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;shopt&lt;/span&gt; -s nullglob
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f in /path/to/files/*; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Found file: &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$f&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another interesting option you may want to check for, supported by Bash since version 3, is &lt;strong&gt;failglob&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;failglob&lt;/strong&gt; enabled, quoting again, “patterns which fail to match filenames during filename expansion result in an expansion error”. Depending on what you need, that could even be a better behavior.&lt;/p&gt;
&lt;p&gt;Wondering why &lt;strong&gt;nullglob&lt;/strong&gt; it’s not the default behavior? Check &lt;a href=&#34;http://unix.stackexchange.com/a/204944/55408&#34;&gt;this very good answer&lt;/a&gt; to the question.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Adding Bash Completion To a Python Script</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/06/adding-bash-completion-to-python-script/"/>
      <id>https://www.endpointdev.com/blog/2016/06/adding-bash-completion-to-python-script/</id>
      <published>2016-06-03T00:00:00+00:00</published>
      <author>
        <name>Szymon Lipiński</name>
      </author>
      <content type="html">
        &lt;p&gt;Bash has quite a nice feature, you can write a command in a console, and then press &lt;TAB&gt; twice. This should should you possible options you can write for this command.&lt;/p&gt;
&lt;p&gt;I will show how to integrate this mechanism into a custom python script with two types of arguments. What’s more, I want this to be totally generic. I don’t want to change it when I will change the options, or change config files.&lt;/p&gt;
&lt;p&gt;This script accepts two types of arguments. One type contains mainly flags beginning with &amp;lsquo;&amp;ndash;&amp;rsquo;, the other type is a host name taken from a bunch of chef scripts.&lt;/p&gt;
&lt;p&gt;Let’s name this script show.py—​it will show some information about the host. This way I can use it with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;show.py szymon&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The szymon part is the name of my special host, and it is taken from one of our chef node definition files.&lt;/p&gt;
&lt;p&gt;This script also takes huge number of arguments like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;show.py --cpu --memory --format=json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So we have two kinds of arguments: one is a simple string, one begins with &amp;ndash;.&lt;/p&gt;
&lt;p&gt;To implement the bash completion on double &lt;TAB&gt;, first I wrote a simple python script, which is prints a huge list of all the node names:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sys&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; argv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;__name__&lt;/span&gt; == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pattern = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;len&lt;/span&gt;(argv) == &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        pattern = argv[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    chef_dir = os.environ.get(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;CHEF_DIR&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;None&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;not&lt;/span&gt; chef_dir:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        exit(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    node_dirs = [os.path.join(chef_dir, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;nodes&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 os.path.join(chef_dir, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dev_nodes&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    node_names = []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; nodes_dir &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; node_dirs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; root, dirs, files &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; os.walk(nodes_dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; f &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; files:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;open&lt;/span&gt;(os.path.join(root, f), &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt; nf:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        data = json.load(nf)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        node_names.append(data[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;][&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;support_name&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;except&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; name &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; node_names:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another thing was to get a list of all the program options. We used the below one liner. It uses the help information shown by the script. So each time the script changed its options, and it is shown when used show.py &amp;ndash;help, the tab completion will have show these new options.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$CHEF_DIR&lt;/span&gt;/repo_scripts/show.py --help | grep &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;  --&amp;#39;&lt;/span&gt; | awk &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The last step to make all this work was making a simple bash script, which uses the above python script, and the one liner. I placed this script in a file $CHEF_DIR/repo_scripts/show.bash-completion.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_show_complete()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#038&#34;&gt;local&lt;/span&gt; cur prev opts node_names
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;COMPREPLY&lt;/span&gt;=()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;cur&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;COMP_WORDS&lt;/span&gt;[COMP_CWORD]&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;prev&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;COMP_WORDS&lt;/span&gt;[COMP_CWORD-1]&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;opts&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$CHEF_DIR&lt;/span&gt;/repo_scripts/show.py --help | grep &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;  --&amp;#39;&lt;/span&gt; | awk &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;node_names&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;python &lt;span style=&#34;color:#369&#34;&gt;$CHEF_DIR&lt;/span&gt;/repo_scripts/node_names.py&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [[ &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;cur&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt; == -* ]] ; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;COMPREPLY&lt;/span&gt;=( &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;compgen&lt;/span&gt; -W &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;opts&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; -- &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;cur&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;COMPREPLY&lt;/span&gt;=( &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;compgen&lt;/span&gt; -W &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;node_names&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; -- &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;${&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;cur&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;complete&lt;/span&gt; -F _show_complete show.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The last thing was to source this file, so I’ve added the below line in my ~/.bashrc.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;source&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$CHEF_DIR&lt;/span&gt;/repo_scripts/show.bash-completion&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now pressing the &lt;TAB&gt; twice in a console shows quite nice completion options:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ show.py &amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Display all &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;42&lt;/span&gt; possibilities? (y or n)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... and here go all &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;42&lt;/span&gt; node names ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/tab&amp;gt;&amp;lt;/tab&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ show.py h&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... and here go all node names beginning with &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;h&amp;#39;&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/tab&amp;gt;&amp;lt;/tab&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ show.py --&amp;lt;tab&amp;gt;&amp;lt;tab&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.. and here go all the options beginning with -- ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/tab&amp;gt;&amp;lt;/tab&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Breaking Bash</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/01/breaking-bash/"/>
      <id>https://www.endpointdev.com/blog/2016/01/breaking-bash/</id>
      <published>2016-01-15T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;Recently I managed to break the bash shell in an interesting and puzzling way. The initial symptoms were very frustrating: a workflow process we use here (creating a development camp) failed for me, but for no one else. That was at least a clue that it was me, not the workflow process.&lt;/p&gt;
&lt;p&gt;Eventually, I narrowed down the culprit to the “grep” command (and that was more through luck than steadfast Sherlock-like detective work).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep foo bar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep: foo: No such file or directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Eh? grep is misparsing the arguments! How does &lt;em&gt;that&lt;/em&gt; happen?&lt;/p&gt;
&lt;p&gt;So I began to study my bash environment. Eventually I came up with this fascinating little typo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;GREP_OPTIONS&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-color=auto&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That&amp;rsquo;s supposed to be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;GREP_OPTIONS&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;--color=auto&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;but it got recorded in my .bashrc as a em-dash, not a double-dash. (My guess is that I cut-and-pasted this from a web page where someone over-helpfully “typeset” this command.)&lt;/p&gt;
&lt;p&gt;Ironically, this typo is innocuous under Bash 3.x, but when you slot it into a Bash 4.x installation, all heck busts loose.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Top 15 Best Unix Command Line Tools</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/11/favourite-unix-command-line-tools/"/>
      <id>https://www.endpointdev.com/blog/2015/11/favourite-unix-command-line-tools/</id>
      <published>2015-11-04T00:00:00+00:00</published>
      <author>
        <name>Ramkumar Kuppuchamy</name>
      </author>
      <content type="html">
        &lt;p&gt;Here are some of the Unix command line tools which we feel make our hands faster and lives easier. Let’s go through them in this post and make sure to leave a comment with your favourite!&lt;/p&gt;
&lt;h3 id=&#34;1-find-the-command-that-you-are-unaware-of&#34;&gt;1. Find the command that you are unaware of&lt;/h3&gt;
&lt;p&gt;In many situations we need to perform a command line operation but we might not know the right utility to run. The command (apropos) searches for the given keyword against its short description in the unix manual page and returns a list of commands that we may use to accomplish our need.&lt;/p&gt;
&lt;p&gt;If you can not find the right utility, then Google is our friend :)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ apropos &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;list dir&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ man -k &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;find files&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-0-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;188&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-0.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;2-fix-typos-in-our-commands&#34;&gt;2. Fix typos in our commands&lt;/h3&gt;
&lt;p&gt;It’s normal to make typographical errors when we type so fast. Consider a situation where we need to run a command with a long list of arguments and when executing it returns “command not found” and you noticed that you have made a typo on the executed command.&lt;/p&gt;
&lt;p&gt;Now, we really do not want to retype the long list of arguments, instead use the following to simply just correct the typo command and execute &lt;code&gt;^typo_cmd^correct_cmd&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ dc /tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ^dc^cd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above will navigate to /tmp directory.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-1-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;182&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-1.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;3-bang-and-its-magic&#34;&gt;3. Bang and its Magic&lt;/h3&gt;
&lt;p&gt;Bang quite useful, when we want to play with the bash history commands. Bang helps by letting you execute commands in history easily when you need them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;!!&lt;/code&gt; — Execute the last executed command in the bash history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!*&lt;/code&gt; — Execute the command with all the arguments passed to the previous command&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!ˆ&lt;/code&gt; — Get the first argument of the last executed command in the bash history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!$&lt;/code&gt; — Get the last argument of the last executed command in the bash history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt; — Execute a command which is in the specified number in bash history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!?keyword?&lt;/code&gt; — Execute a command from bash history for the first pattern match of the specified keyword&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!-N&lt;/code&gt; — Execute the command that was Nth position from the last in bash history&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ~/bin/lg-backup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; $ sudo !!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the last part of the above example we didn’t realize that the lg-backup command had to be run with &lt;code&gt;sudo&lt;/code&gt;. Now, Instead of typing the whole command again with sudo, we can just use &lt;code&gt;sudo !!&lt;/code&gt; which will re-run the last executed command in bash history as sudo, which saves us lot of time.&lt;/p&gt;
&lt;h3 id=&#34;4-working-with-incron&#34;&gt;4. Working with Incron&lt;/h3&gt;
&lt;p&gt;This incron configuration is almost like crontab setup, but the main difference is that incron monitors a directory for specific changes and triggers future actions as specified&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Syntax: &lt;span style=&#34;color:#369&#34;&gt;$directory&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$file_change_mask&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$command_or_action&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/var/www/html/contents/ IN_CLOSE_WRITE,IN_CREATE,IN_DELETE /usr/bin/rsync –exclude ’*.tmp’ -a /home/ram/contents/ user@another_host:/home/ram/contents/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /tmp IN_ALL_EVENTS logger &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/tmp action for #file&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above example shows triggering an rsync event whenever there is a change in &lt;code&gt;/var/www/html/contents&lt;/code&gt; directory. In cases of immediate backup implementations this will be really helpful. Find more about incron &lt;a href=&#34;https://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;5-double-dash&#34;&gt;5. Double dash&lt;/h3&gt;
&lt;p&gt;There are situations where we end up in creating/deleting the directories whose name start with a symbol. These directories can not be removed by just using &lt;code&gt;rm -rf&lt;/code&gt; or &lt;code&gt;rmdir&lt;/code&gt;. So we need to use the “double dash” (&amp;ndash;) to perform deletion of such directories:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rm -rf -- &lt;span style=&#34;color:#369&#34;&gt;$symbol_dir&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are situations where you may want to create a few directory that starts with a symbol. You can just these create directories using double dash(&amp;ndash;) and starting the directory name with a symbol.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir -- &lt;span style=&#34;color:#369&#34;&gt;$symbol_dir&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-2-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;276&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-2.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;6-comma-and-braces-operators&#34;&gt;6. Comma and Braces Operators&lt;/h3&gt;
&lt;p&gt;We can do lot with comma and braces to make our life easier when we are performing some operations, lets see few usages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rename and backup operations with comma &amp;amp; braces operator&lt;/li&gt;
&lt;li&gt;Pattern matching with comma &amp;amp; braces operator&lt;/li&gt;
&lt;li&gt;Rename and backup (prefixing name) operations on long file names&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To backup &lt;code&gt;httpd.conf&lt;/code&gt; to &lt;code&gt;httpd.conf.bak&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp httpd.conf{,.bak}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To revert the file from &lt;code&gt;httpd.conf.bak&lt;/code&gt; to &lt;code&gt;httpd.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv http.conf{.bak,}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To rename the file with prefix “old”:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp exampleFile old-!#ˆ&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-3-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;194&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-3.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;7--read-only-vim&#34;&gt;7.  Read only vim&lt;/h3&gt;
&lt;p&gt;As we all know, vim is a powerful command line editor. We can also use vim to view files in read only mode if you want to stick to vim:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ vim -R filename&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also use the &lt;code&gt;view&lt;/code&gt; tool which is nothing but read only vim:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ view filename&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;8-push-and-pop-directories&#34;&gt;8. Push and Pop Directories&lt;/h3&gt;
&lt;p&gt;Sometimes when we are working with various directories and looking at the logs and executing scripts we find alot of our time is spent navigating the directory structure. If you think your directory navigations resembles a stack structure then use push and pop utilities which will save you lots of time&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push the directory using &lt;code&gt;pushd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;List the stack directories using the command &lt;code&gt;dirs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Pop the directories using &lt;code&gt;popd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;
This is mainly used in navigating between directories:
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-4-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;326&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-4.png&#34; width=&#34;400&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;9-copy-text-from-linux-terminal-stdin-to-the-system-clipboard&#34;&gt;9. Copy text from Linux terminal (stdin) to the system clipboard&lt;/h3&gt;
&lt;p&gt;Install xclip and create the below alias:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pbcopy&lt;/span&gt;=’xclip -selection clipboard’
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#038&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pbpaste&lt;/span&gt;=’xclip -selection clipboard -o’&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We need to have the X window system running it to work. In Mac OS X, these pbcopy and pbpaste commands are readily available to you.&lt;/p&gt;
&lt;p&gt;To Copy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls | pbcopy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To Paste:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pbpaste &amp;gt; lstxt.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;10-timemachine-like-incremental-backups-in-linux-using-rsync-link-dest&#34;&gt;10. TimeMachine like Incremental Backups in Linux using rsync &amp;ndash;link-dest&lt;/h3&gt;
&lt;p&gt;This means that it will not recopy all of the files every single time a backup is performed. Instead, only the files that have been newly created or modified since the last backup will be copied. Unchanged files are hard linked from prevbackup to the destination directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rsync -a –link-dest=prevbackup src dst&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;11-to-display-the-ascii-art-of-the-process-tree&#34;&gt;11. To display the ASCII art of the Process tree&lt;/h3&gt;
&lt;p&gt;Showing your processes in a tree structure is very useful for confirming the relationship between every process running on your system. Here is an option which is available by default on most of the Linux systems:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -aux –forest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;–forest&lt;/code&gt; is an argument to &lt;code&gt;ps&lt;/code&gt; command, which displays ASCII art of process tree:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-5-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;74&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-5.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br/&gt;
&lt;p&gt;There are many commands available like &lt;code&gt;pstree&lt;/code&gt; and &lt;code&gt;htop&lt;/code&gt; to achieve the same thing.&lt;/p&gt;
&lt;h3 id=&#34;12-tree-view-of-git-commits&#34;&gt;12. Tree view of git commits&lt;/h3&gt;
&lt;p&gt;If you want to see git commits in a repo as tree view to understand the commit history better, the below option will be super helpful. This is available with the git installation and you do not need any additional packages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git log –graph –oneline&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;13-tee&#34;&gt;13. Tee&lt;/h3&gt;
&lt;p&gt;Tee command is used to store and view (at the same time) the output of any other command.&lt;/p&gt;
&lt;p&gt;(ie) At the same time it writes to the STDOUT, and to a file. It helps when you want to view the command output and at the time same time if you want to write it into a file or using pbcopy you can copy the output&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ crontab -l | tee crontab.backup.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The tee command is named after plumbing terminology for a T-shaped pipe splitter. This Unix command splits the output of a command, sending it to a file and to the terminal output. Thanks Jon for sharing this.&lt;/p&gt;
&lt;h3 id=&#34;14-ncurses-disk-usage-analyzer&#34;&gt;14. ncurses disk usage analyzer&lt;/h3&gt;
&lt;p&gt;Analysing disk usage with nurses interface, is fast and simple to use.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install ncdu&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-6-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;313&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-6.png&#34; width=&#34;400&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;15-hollywood&#34;&gt;15. hollywood&lt;/h3&gt;
&lt;p&gt;You all have seen the hacking scene on hollywood movies. Yes, there is a package which will let you create that for you.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-add-repository ppa:hollywood/ppa
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo apt-get install hollywood&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ hollywood&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-7-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;350&#34; src=&#34;/blog/2015/11/favourite-unix-command-line-tools/image-7.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;

      </content>
    </entry>
  
    <entry>
      <title>Getting realtime output using Python Subprocess</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/01/getting-realtime-output-using-python/"/>
      <id>https://www.endpointdev.com/blog/2015/01/getting-realtime-output-using-python/</id>
      <published>2015-01-28T00:00:00+00:00</published>
      <author>
        <name>Kannan Ponnusamy</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;the-problem&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;When I launch a long running unix process within a python script, it waits until the process is finished, and only then do I get the complete output of my program. This is annoying if I’m running a process that takes a while to finish. And I want to capture the output and display it in the nice manner with clear formatting.&lt;/p&gt;
&lt;h3 id=&#34;using-the-subprocess-and-shlex-library&#34;&gt;Using the subprocess and shlex library&lt;/h3&gt;
&lt;p&gt;Python has a “batteries included” philosophy. I have used 2 standard libraries to solve this problem.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;shlex&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;subprocess—​Works with additional processes.&lt;/li&gt;
&lt;li&gt;shlex—​Lexical analysis of shell-style syntaxes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;subprocesspopen&#34;&gt;subprocess.popen&lt;/h3&gt;
&lt;p&gt;To run a process and read all of its output, set the stdout value to PIPE and call communicate().&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;process = subprocess.Popen([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;echo&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#34;Hello stdout&amp;#34;&amp;#39;&lt;/span&gt;], stdout=subprocess.PIPE)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stdout = process.communicate()[&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;STDOUT:&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;.format(stdout)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above script will wait for the process to complete and then it will display the output. So now we are going to read the stdout line by line and display it in the console untill it completes the process.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;output = process.stdout.readline()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will read a line from the stdout.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;process.poll()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The poll() method will return&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the exit code if the process is completed.&lt;/li&gt;
&lt;li&gt;None if the process is still running.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        output = process.stdout.readline()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; output == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;and&lt;/span&gt; process.poll() &lt;span style=&#34;color:#080&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; output:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; output.strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rc = process.poll()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above will loop and keep on reading the stdout and check for the return code and displays the output in real time.&lt;/p&gt;
&lt;p&gt;I had one more problem in parsing the shell commands to pass it to popen when I set the shell=False.  Below is an example command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync -avzXH --delete --exclude=*.swp --exclude=**/drivers.ini /media/lgisos/lg.iso root@42-a:/isodevice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To split the string using shell-like syntax I have used shlex library’s split method.&lt;/p&gt;
&lt;h3 id=&#34;here-is-the-final-code-looks-like&#34;&gt;Here is the final code looks like&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;run_command&lt;/span&gt;(command):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        output = process.stdout.readline()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; output == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;and&lt;/span&gt; process.poll() &lt;span style=&#34;color:#080&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; output:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; output.strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rc = process.poll()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; rc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>MySQL to PostgreSQL Migration Tips</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/11/mysql-to-postgresql-migration-tips/"/>
      <id>https://www.endpointdev.com/blog/2014/11/mysql-to-postgresql-migration-tips/</id>
      <published>2014-11-26T00:00:00+00:00</published>
      <author>
        <name>David Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;I recently was involved in a project to migrate a client’s existing application from MySQL to PostgreSQL, and I wanted to record some of my experiences in doing so in the hopes they would be useful for others.&lt;/p&gt;
&lt;p&gt;Note that these issues should not be considered exhaustive, but were taken from my notes of issues encountered and/or things that we had to take into consideration in this migration process.&lt;/p&gt;
&lt;h3 id=&#34;convert-the-schema&#34;&gt;Convert the schema&lt;/h3&gt;
&lt;p&gt;The first step is to convert the equivalent schema in your PostgreSQL system, generated from the original MySQL.&lt;/p&gt;
&lt;p&gt;We used &lt;code&gt;mysqldump --compatible=postgresql --no-data&lt;/code&gt; to get a dump which matched PostgreSQL’s quoting rules. This file still required some manual editing to cleanup some of the issues, such as removing MySQL’s “Engine” specification after a CREATE TABLE statement, but this resulted in a script in which we were able to create a skeleton PostgreSQL database with the correct database objects, names, types, etc.&lt;/p&gt;
&lt;p&gt;Some of the considerations here include the database collations/charset. MySQL supports multiple collations/charset per database; in this case we ended up storing everything in UTF-8, which matched the encoding of the PostgreSQL database, so there were no additional changes needed here; otherwise, it would have been necessary to note the original encoding of the individual tables and later convert that to UTF-8 in the next step.&lt;/p&gt;
&lt;p&gt;We needed to make the following modifications for datatypes:&lt;/p&gt;
&lt;table style=&#34;border: 1px;&#34;&gt;&lt;tbody&gt;&lt;tr&gt;     &lt;th&gt;MySQL Datatype&lt;/th&gt;     &lt;th&gt;PostgreSQL Datatype&lt;/th&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;tinyint&lt;/td&gt;     &lt;td&gt;int&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;int(&lt;i&gt;NN&lt;/i&gt;)&lt;/td&gt;     &lt;td&gt;int&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;blob&lt;/td&gt;     &lt;td&gt;bytea*&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;datetime&lt;/td&gt;     &lt;td&gt;timestamp with timezone&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;int unsigned&lt;/td&gt;     &lt;td&gt;int**&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;enum(&#39;1&#39;)&lt;/td&gt;     &lt;td&gt;bool&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;longtext&lt;/td&gt;     &lt;td&gt;text&lt;/td&gt;   &lt;/tr&gt;
&lt;tr&gt;     &lt;td&gt;varbinary(&lt;i&gt;NN&lt;/i&gt;)&lt;/td&gt;     &lt;td&gt;bytea&lt;/td&gt;   &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;* Note: we ended up converting these specific fields to text, just given the data that was stored in these fields in actuality, which just goes to show you should review your data.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;** Note: because PostgreSQL does not have unsigned numeric types, if this feature is an important part of your data model you can/should add a CHECK constraint to the column in question to check that the value is non-negative.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A few other syntactic changes; MySQL’s UNIQUE KEY in the CREATE TABLE statement needs to just be UNIQUE.&lt;/p&gt;
&lt;p&gt;Some of the MySQL indexes were defined as FULLTEXT indexes as well, which was a keyword PostgreSQL did not recognize. We made note of these, then created just normal indexes for the time being, intending to review to what extent these actually needed full text search capabilities.&lt;/p&gt;
&lt;p&gt;Some of the AUTO_INCREMENT fields did not get the DEFAULT value set correctly to a sequence, because those types just ended up as integers without being declared a serial field, so we used the following query to correct this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;-- cleanup missing autoincrement fields
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WITH&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;datasource&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;k.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;k.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;column_name&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;atttypid::regtype,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;adsrc&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;information_schema.key_column_usage&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;k&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;JOIN&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;pg_attribute&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;ON&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;attrelid&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;k.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;::&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;regclass&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AND&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;attname&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;k.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;column_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;LEFT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;JOIN&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;pg_attrdef&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;ON&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;adrelid&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;k.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;::&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;regclass&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AND&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;adnum&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;k.ordinal_position&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;IN&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;::&lt;span style=&#34;color:#038&#34;&gt;text&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;information_schema.key_column_usage&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;constraint_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;LIKE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;%_pkey&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;GROUP&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BY&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;HAVING&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;count&lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AND&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;adsrc&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;IS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;NULL&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AND&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;atttypid&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;integer&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;::regtype&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;),&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;frags&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;quote_ident(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;column_name&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;_seq&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_seqname,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;quote_ident(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table_name&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_table,&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;quote_ident(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;column_name&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_col&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;datasource&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;),&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;queries&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;CREATE SEQUENCE &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_seqname&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;ALTER TABLE &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_table&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; ALTER COLUMN &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_col&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SET&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;DEFAULT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;nextval(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;$$ || q_seqname || $$&amp;#39;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;setval(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;$$ || q_seqname || $$&amp;#39;&lt;/span&gt;,(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;max&lt;/span&gt;(&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_col&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;) FROM &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;q_table&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;||&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;));
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;query&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;frags&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;COALESCE(string_agg(query,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;E&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;),&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;No autoincrement fixes needed&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;$$&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;queries&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;queries&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;\&lt;/span&gt;gset&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;:queries&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;COMMIT&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Basically the idea is that we look for all table with a defined integer primary key (hand-waving it it by using the _pkey suffix in the constraint name), but without a current default value, then generate the equivalent SQL to create a sequence and set that table’s default value to the nextval() for the sequence in question. We also generate SQL to scan that table and set that sequence value to the next appropriate value for the column in question. (Since this is for a migration and we know we’ll be the only user accessing these tables we can ignore MVCC.)&lt;/p&gt;
&lt;p&gt;Another interesting thing about this script is that we utilize psql’s ability to store results in a variable, using the \gset command, then we subsequently execute this SQL by interpolating that corresponding variable in the same script.&lt;/p&gt;
&lt;h3 id=&#34;convert-the-data&#34;&gt;Convert the data&lt;/h3&gt;
&lt;p&gt;The next step was to prepare the data load from a MySQL data-only dump. Using a similar dump recipe as for the initial import, we used: &lt;code&gt;mysqldump --compatible=postgresql --no-create-info --extended-insert &amp;gt; data.sql&lt;/code&gt; to save the data in a dump file so we could iteratively tweak our approach to cleaning up the MySQL data.&lt;/p&gt;
&lt;p&gt;Using our dump file, we attempted a fresh load into the new PostgreSQL database. This failed initially due to multiple issues, including ones of invalid character encoding and stricter datatype interpretations in PostgreSQL.&lt;/p&gt;
&lt;p&gt;What we ended up doing was to create a filter script to handle all of the “fixup” issues needed here. This involved decoding the data and reencoding to ensure we were using proper UTF8, performing some context-sensitive datatype conversions, etc.&lt;/p&gt;
&lt;h3 id=&#34;additional-schema-modifications&#34;&gt;Additional schema modifications&lt;/h3&gt;
&lt;p&gt;As we were already using a filter script to process the data dump, we decided to take the opportunity to fixup some warts in the current table definitions. This included some fields which were varchar, but should have actually been numeric or integer; as this was a non-trivial schema (100 tables) we were able to use PostgreSQL’s system views to identify a list of columns which should should be numeric and were currently not.&lt;/p&gt;
&lt;p&gt;Since this was an ecommerce application, we identified columns that were likely candidates for data type reassignment based on field names *count, *qty, *price, *num.&lt;/p&gt;
&lt;p&gt;Once we identified the fields in question, I wrote a script to generate the appropriate ALTER TABLE statements to first drop the default, change the column type, then set the new default. This was done via a mapping between table/column name and desired output type.&lt;/p&gt;
&lt;h3 id=&#34;convert-the-application&#34;&gt;Convert the application&lt;/h3&gt;
&lt;p&gt;The final (and needless to say most involved step) was to convert the actual application itself to work with PostgreSQL. Despite the fact that these databases both speak SQL, we had to come up for solutions for the following issues:&lt;/p&gt;
&lt;h3 id=&#34;quotation-styles&#34;&gt;Quotation styles&lt;/h3&gt;
&lt;p&gt;MySQL is more lax with its quoting styles, so some of this migration involved hunting down differences in quoting styles. The codebase contained lots of double-quoted string literals, which PostgreSQL interprets as identifiers, as well as the difference in quoting of column names (backticks for MySQL, double-quotes for PostgreSQL). These had to be identified wherever they appeared and fixed to use a consistent quoting style.&lt;/p&gt;
&lt;h3 id=&#34;specific-unsupported-syntax-differences&#34;&gt;Specific unsupported syntax differences:&lt;/h3&gt;
&lt;h4 id=&#34;insert-on-duplicate-key&#34;&gt;INSERT ON DUPLICATE KEY&lt;/h4&gt;
&lt;p&gt;MySQL supports the INSERT ON DUPLICATE KEY syntax. Modifying these queries involved creating a special UPSERT-style function to support the different options in use in the code base. We isolated and categorized the uses of INSERT ON DUPLICATE KEY UPDATE into several categories: those which did a straight record replace and those which did some sort of modification. I wrote a utility script (detailed later in this article) which served to replicate the logic needed to handle this as the application would expect.&lt;/p&gt;
&lt;p&gt;Upcoming versions of PostgreSQL are likely to incorporate an INSERT &amp;hellip; ON CONFLICT UPDATE/IGNORE syntax, which would produce a more direct method of handling migration of these sorts of queries.&lt;/p&gt;
&lt;h4 id=&#34;insert-ignore&#34;&gt;INSERT IGNORE&lt;/h4&gt;
&lt;p&gt;MySQL’s INSERT &amp;hellip; IGNORE syntax allows you to insert a row and effectively ignore a primary key violation, assuming that the rest of the row is valid. You can handle this case via creating a similar UPSERT function as in the previous point. Again, this case will be easily resolved if PostgreSQL adopts the INSERT &amp;hellip; ON CONFLICT IGNORE syntax.&lt;/p&gt;
&lt;h4 id=&#34;replace-into&#34;&gt;REPLACE INTO&lt;/h4&gt;
&lt;p&gt;MySQL’s REPLACE INTO syntax effectively does a DELETE followed by an INSERT; it basically ensures that a specific version of a row exists for the given primary key value. We handle this case by just modifying these queries to do an unconditional DELETE for the Primary Key in question followed by the corresponding INSERT. We ensure these are done within a single transaction so the result is atomic.&lt;/p&gt;
&lt;h4 id=&#34;interval-syntax&#34;&gt;INTERVAL syntax&lt;/h4&gt;
&lt;p&gt;Date interval syntax can be slightly different in MySQL; intervals may be unquoted in MySQL, but &lt;strong&gt;must&lt;/strong&gt; be quoted in PostgreSQL. This project necessitated hunting down several instances to add quoting of specific literal INTERVAL instances.&lt;/p&gt;
&lt;h3 id=&#34;function-considerations&#34;&gt;Function considerations&lt;/h3&gt;
&lt;h4 id=&#34;last_insert_id&#34;&gt;last_insert_id()&lt;/h4&gt;
&lt;p&gt;Many times when you insert a records into a MySQL table, later references to this are found using the last_insert_id() SQL function. These sorts of queries need to be modified to utilize the equivalent functionality using PostgreSQL sequences, such as the currval() function.&lt;/p&gt;
&lt;h4 id=&#34;group_concat&#34;&gt;GROUP_CONCAT()&lt;/h4&gt;
&lt;p&gt;MySQL has the GROUP_CONCAT function, which serves as a string “join” of sorts. We emulate this behavior in PostgreSQL by using the string_agg aggregate function with the delimiter of choice.&lt;/p&gt;
&lt;h4 id=&#34;concat_ws--expected-to-be-but-not-an-issue-postgres-has-this-function&#34;&gt;CONCAT_WS() — expected to be but not an issue; Postgres has this function&lt;/h4&gt;
&lt;p&gt;PostgreSQL has included a CONCAT_WS() function since PostgreSQL 9.1, so this was not an issue with the specific migration, but could still be an issue if you are migrating to an older version of PostgreSQL.&lt;/p&gt;
&lt;h4 id=&#34;str_to_date&#34;&gt;str_to_date()&lt;/h4&gt;
&lt;p&gt;This function does not exist directly in PostgreSQL, but can be simulated using to_date(). Note however that the format string argument differs between MySQL and PostgreSQL’s versions.&lt;/p&gt;
&lt;h4 id=&#34;date_format&#34;&gt;date_format()&lt;/h4&gt;
&lt;p&gt;MySQL has a date_format() function which transforms a date type to a string with a given format option. PostgreSQL has similar functionality using the to_char() function; the main difference here lies in the format string specifier.&lt;/p&gt;
&lt;h4 id=&#34;datediff&#34;&gt;DateDiff()&lt;/h4&gt;
&lt;p&gt;DateDiff() does not exist in PostgreSQL, this is handled by transforming the function call to the equivalent date manipulation operators using the subtraction (-) operator.&lt;/p&gt;
&lt;h4 id=&#34;rand-to-random&#34;&gt;rand() to random()&lt;/h4&gt;
&lt;p&gt;This is more-or-less a simple function rename, as the equivalent functionality for returning a random float between 0.0 &amp;lt;= x &amp;lt;= 1.0 exists in PostgreSQL and MySQL, it’s just what the function name itself is. The other difference is that MySQL supports a scale argument so the random number for rand(&lt;em&gt;N&lt;/em&gt;) will be returned between 0.0 &amp;lt;= x &amp;lt;= N, whereas you’d have to scale the result in PostgreSQL yourself, via random() * N.&lt;/p&gt;
&lt;h4 id=&#34;if-to-case-when-else&#34;&gt;IF() to CASE WHEN ELSE&lt;/h4&gt;
&lt;p&gt;MySQL has an IF() function which returns the second argument in the case the first argument evaluates to true otherwise returns the third argument. This can be trivially converted from IF(expression1, arg2, arg3) to the equilvalent PostgreSQL syntax: CASE WHEN expression1 THEN arg2 ELSE arg3.&lt;/p&gt;
&lt;h4 id=&#34;ifnull-to-coalesce&#34;&gt;IFNULL() to COALESCE()&lt;/h4&gt;
&lt;p&gt;MySQL has a function IFNULL() which returns the first argument if it is not NULL, otherwise it returns the second argument. This can effectively be replaced by the PostgreSQL COALESCE() function, which serves the same purpose.&lt;/p&gt;
&lt;h4 id=&#34;split_part&#34;&gt;split_part()&lt;/h4&gt;
&lt;p&gt;MySQL has a built-in function called split_part() which allows you to access a specific index of an array delimited by a string. PostgreSQL also has this function, however the split_part() function in MySQL allows the index to be negative, in which case this returns the part from the right-hand side.&lt;/p&gt;
&lt;p&gt;in MySQL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;split_part(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;a banana boat&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;boat&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;in PostgreSQL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;split_part(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;a banana boat&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;-&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;//&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;ERROR:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;field&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;must&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;be&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;greater&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;than&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;zero&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I fixed this issue by creating a custom PL/pgSQL function to handle this case. (In my specific case, all of the negative indexes were -1; i.e., the last element in the array, so I created a function to return only the substring occurring after the last instance of the delimiter.)&lt;/p&gt;
&lt;h3 id=&#34;performance-considerations&#34;&gt;Performance considerations&lt;/h3&gt;
&lt;h4 id=&#34;you-may-need-to-revisit-count-queries&#34;&gt;You may need to revisit COUNT(*) queries&lt;/h4&gt;
&lt;p&gt;MySQL MyISAM tables have a very fast COUNT(&lt;em&gt;) calculation, owing to queries taking a table lock (which means MySQL can cache the COUNT(&lt;/em&gt;) result itself, since there can be no concurrent updates), while PostgreSQL utilizes MVCC in order to calculate table counts which necessitates a full table scan to see which rows are visible to the specific calling snapshot, so this assumption may need to be revisited in order to calculate an equivalent performant query.&lt;/p&gt;
&lt;h4 id=&#34;group-by-vs-distinct-on&#34;&gt;GROUP BY vs DISTINCT ON&lt;/h4&gt;
&lt;p&gt;MySQL is much more (&lt;em&gt;ahem&lt;/em&gt;) flexible when it comes to GROUP BY/aggregate queries, allowing some columns to be excluded in a GROUP BY or an aggregate function. Making the equivalent query in PostgreSQL involves transforming the query from SELECT &amp;hellip; GROUP BY (cols) to a SELECT DISTINCT ON (cols) &amp;hellip; and providing an explicit sort order for the rows.&lt;/p&gt;
&lt;h3 id=&#34;more-notes&#34;&gt;More notes&lt;/h3&gt;
&lt;p&gt;Don’t be afraid to script things; in fact, I would go so far as to suggest that &lt;strong&gt;everything&lt;/strong&gt; you do should be scripted. This process was complicated and there were lots of moving parts to ensure moved in tandem. There were changes being made on the site itself concurrently, so we were doing testing against a dump of the original database at a specific point-in-time. Having everything scripted ensured that this process was repeatable and testable, and that we could get to a specific point in the process without having to remember anything I’d done off-the-cuff.&lt;/p&gt;
&lt;p&gt;In addition to scripting the actual SQL/migrations, I found it helpful to script the solutions to various classifications of problems. I wrote some scripts which I used to create some of the various scaffolding/boilerplate for the tables involved. This included a script which would create an UPSERT function for a specific table given the table name, which was used when replacing the INSERT ON DUPLICATE KEY UPDATE functions. This generated script could then be tailored to handle more complex logic beyond a simple UPDATE. (One instance here is an INSERT ON DUPLICATE KEY UPDATE which increased the count of a specific field in the table instead of replacing the value.)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# -*-cperl-*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;strict&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;warnings&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Data::Dumper&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$table&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;shift&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Usage: $0 &amp;lt;table&amp;gt;\n&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;@ARGV&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$dbh&lt;/span&gt; = &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;DBI&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#038&#34;&gt;connect&lt;/span&gt;(...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@raw_cols&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;@&lt;/span&gt;{ &lt;span style=&#34;color:#369&#34;&gt;$dbh&lt;/span&gt;-&amp;gt;column_info(&lt;span style=&#34;color:#038&#34;&gt;undef&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$table&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt;)-&amp;gt;fetchall_arrayref({}) };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;%raw_cols&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;map&lt;/span&gt; { &lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt;-&amp;gt;{COLUMN_NAME} =&amp;gt; &lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt; } &lt;span style=&#34;color:#369&#34;&gt;@raw_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Can&amp;#39;t find table $table\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@raw_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@missing_cols&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;grep&lt;/span&gt; { ! &lt;span style=&#34;color:#038&#34;&gt;defined&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$raw_cols&lt;/span&gt;{&lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt;} } &lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Referenced non-existing columns: @missing_cols\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@missing_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;%is_pk&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;unless&lt;/span&gt; (&lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;map&lt;/span&gt; { &lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt;-&amp;gt;{COLUMN_NAME} } &lt;span style=&#34;color:#369&#34;&gt;@raw_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@pk_cols&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$dbh&lt;/span&gt;-&amp;gt;primary_key(&lt;span style=&#34;color:#038&#34;&gt;undef&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;public&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$table&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;@is_pk&lt;/span&gt;{&lt;span style=&#34;color:#369&#34;&gt;@pk_cols&lt;/span&gt;} = (&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;)x&lt;span style=&#34;color:#369&#34;&gt;@pk_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@data_cols&lt;/span&gt; = &lt;span style=&#34;color:#038&#34;&gt;grep&lt;/span&gt; { ! &lt;span style=&#34;color:#369&#34;&gt;$is_pk&lt;/span&gt;{&lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt;} } &lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Missing PK cols from column list!\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@pk_cols&lt;/span&gt; == &lt;span style=&#34;color:#038&#34;&gt;grep&lt;/span&gt; { &lt;span style=&#34;color:#369&#34;&gt;$is_pk&lt;/span&gt;{&lt;span style=&#34;color:#369&#34;&gt;$_&lt;/span&gt;} } &lt;span style=&#34;color:#369&#34;&gt;@cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;die&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;No data columns!\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;unless&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;@data_cols&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;EOF&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;CREATE OR REPLACE FUNCTION
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    upsert_$table (@{[
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    join &amp;#39;, &amp;#39; =&amp;gt; map {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        &amp;#34;_$_ $raw_cols{ $_ }-&amp;gt;{pg_type}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    } @cols
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;]})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;RETURNS void
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;LANGUAGE plpgsql
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;AS \$EOSQL\$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    LOOP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        UPDATE $table SET @{[
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    join &amp;#39;, &amp;#39; =&amp;gt; map { &amp;#34;$_ = _$_&amp;#34; } @data_cols
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;]} WHERE @{[
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    join &amp;#39; AND &amp;#39; =&amp;gt; map { &amp;#34;$_ = _$_&amp;#34; } @pk_cols
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;]};
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        IF FOUND THEN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;            RETURN;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        END IF;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;            INSERT INTO $table (@{[join &amp;#39;,&amp;#39; =&amp;gt; @cols]}) VALUES (@{[join &amp;#39;,&amp;#39; =&amp;gt; map { &amp;#34;_$_&amp;#34; } @cols]});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;            RETURN;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        EXCEPTION WHEN unique_violation THEN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;            -- Do nothing, and loop to try the UPDATE again.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;        END;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    END LOOP;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;\$EOSQL\$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This script created an upsert function from a given table to update all columns by default, also allowing you to create one with a different number of columns upserted.&lt;/p&gt;
&lt;p&gt;I also wrote scripts which could handle/validate some of the column datatype changes. Since there were large numbers of columns which were changed, often multiple in the same table, I was able to have this script create a single ALTER TABLE statement with multiple ALTER COLUMN TYPE USING clauses, plus be able to specify the actual method that these column changes were to take place. These included several different approaches, depending on the target data type, but generally were to solve cases where there were fairly legitimate data that was not picked up by PostgreSQL’s input parsers. These included how to interpret blank fields as integers (in some cases we wanted it to be 0, in others we wanted it to be NULL), weird numeric formatting (leaving off numbers before or after the decimal point), etc.&lt;/p&gt;
&lt;p&gt;We had to fix up in several locations missing defaults for AUTO_INCREMENT columns. The tables were created with the proper datatype, however we had to find tables which matched a specific naming convention and create/associate a sequence/serial column, set the proper default here, etc. (This was detailed above.)&lt;/p&gt;
&lt;p&gt;There was a fair amount of iteration and customization in this process, as there was a fair amount of data which was not of the expected format. The process was iterative, and generally involved attempting to alter the table from within a transaction and finding the next datum which the conversion to the expected type did not work. This would result in a modification of the USING clause of the ALTER TABLE ALTER COLUMN TYPE to accommodate some of the specific issues.&lt;/p&gt;
&lt;p&gt;In several cases, there were only a couple records which had bad/bunko data, so I included explicit UPDATE statements to update those data values via primary key. While this felt a bit “impure”, it was a quick and preferred solution to the issue of a few specific records which did not fit general rules.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Python Subprocess Wrapping with sh</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/07/python-subprocess-wrapping-with-sh/"/>
      <id>https://www.endpointdev.com/blog/2014/07/python-subprocess-wrapping-with-sh/</id>
      <published>2014-07-24T00:00:00+00:00</published>
      <author>
        <name>Kirk Harr</name>
      </author>
      <content type="html">
        &lt;p&gt;When working with shell scripts written in bash/csh/etc. one of the primary tools you have to rely on is a simple method of piping output and input from subprocesses called by the script to create complex logic to accomplish the goal of the script. When working with python, this same method of calling subprocesses to redirect the input/output is available, but the overhead of using this method in python would be so cumbersome as to make python a less desirable scripting language. In effect you were implementing large parts of the I/O facilities, and potentially even writing replacements for the existing shell utilities that would perform the same work. Recently, python developers attempted to solve this problem, by updating an existing python subprocess wrapper library called pbs, into an easier to use library called sh.&lt;/p&gt;
&lt;p&gt;Sh can be installed using pip, and the author has posted some documentation for the library here: &lt;a href=&#34;http://amoffat.github.io/sh/&#34;&gt;http://amoffat.github.io/sh/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;using-the-sh-library&#34;&gt;Using the sh library&lt;/h3&gt;
&lt;p&gt;After installing the library into your version of python, there will be two ways to call any existing shell command available to the system, firstly you can import the command as though it was itself a python library:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sh&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; hostname
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt;(hostname())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition, you can also call the command directly by just referencing the sh namespace prior to the command name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt;(sh.hostname())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When running this command on my linux workstation (hostname atlas) it will return the expected results:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Python &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.7.6&lt;/span&gt; (default, Mar &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2014&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;59&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;56&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[GCC &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4.8.2&lt;/span&gt;] on linux2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;help&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;copyright&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;credits&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; more information.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt;(sh.hostname())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;atlas&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However at this point, we are merely replacing a single shell command which prints output to the screen, the real benefit of the shell scripts was that you could chain together commands in order to create complex logic to help you do work.&lt;/p&gt;
&lt;h3 id=&#34;advanced-gymnastics&#34;&gt;Advanced Gymnastics&lt;/h3&gt;
&lt;p&gt;A common use of shell scripts is to provide administrators the ability to quickly filter log file output and to potentially search for specific conditions within those logs, to alert in the event that an application starts throwing errors. With python piping in sh we can create a simple log watcher, which would be capable of calling anything we desire in python when the log file contains any of the conditions we are looking for.&lt;/p&gt;
&lt;p&gt;To pipe together commands using the sh library, you would encapsulate each command in series to create a similar syntax to bash piping:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt;(sh.wc(sh.ls(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;-l&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/etc&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;-l&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;199&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command would have been equivalent to the bash pipe of “ls -l /etc | wc -l” indicating that the long listing of /etc on my workstation contained 199 lines of output. Each piped command is encapsulated inside the parenthesis of the command the precedes it.&lt;/p&gt;
&lt;p&gt;For our log listener we will use the tail command along with a python iterator to watch for a potential error condition, which I will represent with the string “ERROR”:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; line &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; sh.tail(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;-f&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/tmp/test_log&amp;#34;&lt;/span&gt;, _iter=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;True&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ERROR&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;in&lt;/span&gt; line:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...         &lt;span style=&#34;color:#038&#34;&gt;print&lt;/span&gt; line&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, once executed, python will call the tail command to follow a particular log file. It will iterate over each line of output produced by tail and if any of the lines contain the string we are watching for python will print that line to standard output. At this point, this would be similar to using the tail command and piping the output to a string search command, like grep. However, you could replace the third line of the python with a more complex action, emailing the error condition out to a developer or administrator for review, or perhaps initiating a procedure to recover from the error automatically.&lt;/p&gt;
&lt;h3 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;In this manner with just a few lines of python, much like with bash, one could create a relatively complex process without recreating all the shell commands which already perform this work, or create a convoluted wrapping process of passing output from command to command. This combination of the existing shell commands and the power of python; you get all the functions available to any python environment, with the ease of using the shell commands to do some of the work. In the future I will definitely be using this python library for my own shell scripting needs, as I have generally preferred the syntax and ease of use of python over that of bash, but now I will be able to enjoy both at the same time.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Version differences via GitHub from the command line</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/07/version-differences-via-github-from/"/>
      <id>https://www.endpointdev.com/blog/2014/07/version-differences-via-github-from/</id>
      <published>2014-07-09T00:00:00+00:00</published>
      <author>
        <name>Greg Sabino Mullane</name>
      </author>
      <content type="html">
        &lt;div class=&#34;separator&#34; style=&#34;clear: both; float:right; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/07/version-differences-via-github-from/image-0.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/07/version-differences-via-github-from/image-0.jpeg&#34;/&gt;&lt;/a&gt;&lt;br/&gt;&lt;small&gt;&lt;a href=&#34;https://flic.kr/p/7pSEW1&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://www.flickr.com/photos/bensonkua/&#34;&gt;Benson Kua&lt;/a&gt;&lt;/small&gt;&lt;/div&gt;
&lt;p&gt;I work with a lot of open source projects, and I use the command-line for almost everything. It often happens that I need to examine a file from a project, and thanks to bash, &lt;a href=&#34;https://github.com/&#34;&gt;Github&lt;/a&gt;, and curl, I can do so easily, without even needing to have the repo handy. One of the things I do sometimes is compare a file across versions to see what has changed. For example, I needed to see what changes were made between versions 1.22 and 1.23 to the file includes/UserMailer.php which is part of the &lt;a href=&#34;https://www.mediawiki.org/wiki/MediaWiki&#34;&gt;MediaWiki&lt;/a&gt; project. For this trick to work, the project must be on Github, and must label their versions in a consistent manner, either via git branches or git tags.&lt;/p&gt;
&lt;p&gt;MediaWiki exists on Github as &lt;a href=&#34;https://github.com/wikimedia/mediawiki-core&#34;&gt;wikimedia/mediawiki-core&lt;/a&gt;. The MediaWiki project tags all of their releases in the format X.Y.Z, so in this example we can use the git tags &lt;strong&gt;1.22.0&lt;/strong&gt; and &lt;strong&gt;1.23.0&lt;/strong&gt;. Github is very nice because you can view a specific file at a certain commit (aka a tag), and even grab it over the web as a plain text file. The format is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://raw.githubusercontent.com/PROJECTNAME/BRANCH-OR-TAG/FILE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that you can use a tag &lt;em&gt;&lt;strong&gt;OR&lt;/strong&gt;&lt;/em&gt; a branch! So to compare these two files, we can use one of these pairs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://raw.githubusercontent.com/wikimedia/mediawiki-core/REL1_21/includes/UserMailer.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://raw.githubusercontent.com/wikimedia/mediawiki-core/REL1_22/includes/UserMailer.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://raw.githubusercontent.com/wikimedia/mediawiki-core/1.21.0/includes/UserMailer.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://raw.githubusercontent.com/wikimedia/mediawiki-core/1.22.0/includes/UserMailer.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All that is left is to treat git as a web service and compare the two files at the command line ourselves. The program &lt;strong&gt;curl&lt;/strong&gt; is a great tool for downloading the files, as it dumps to stdout by default. We will add a &lt;strong&gt;-s&lt;/strong&gt; flag (for “silent”) to prevent it from showing the progress meter as it usually does. The last bit of the puzzle is to use &amp;lt;(), bash’s process substitution feature, to trick diff into comparing the curl outputs as if they were files. So our final command is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;diff &amp;lt;(curl -s https://raw.githubusercontent.com/wikimedia/mediawiki-core/1.21.0/includes/UserMailer.php) \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;(curl -s https://raw.githubusercontent.com/wikimedia/mediawiki-core/1.22.0/includes/UserMailer.php) \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| more&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Voila! A quick and simple glance at what changed between those two tags. This should work for any project on Github. You can also replace the branch or tag with the word “master” to see the current version. For example, the PostgreSQL project lives on github as postgres/postgres. They use the format RELX_Y_Z in their tags. To see what has changed since release 9.3.4 in the psql help file (as a context diff), run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;diff&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;-&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&amp;lt;(curl&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;-s&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;https://raw.githubusercontent.com/postgres/postgres/REL9_3_4/src/bin/psql/help.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;c&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&amp;lt;(curl&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;-s&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;https://raw.githubusercontent.com/postgres/postgres/master/src/bin/psql/help.&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;c&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You are not limited to diff, of course. For a final example, let’s see how many times Tom Lane is mentioned in the version 9 release notes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;for i in {0,1,2,3,4}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;do grep -Fc &amp;#39;Tom Lane&amp;#39; \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;(curl -s https://raw.githubusercontent.com/postgres/postgres/master/doc/src/sgml/release-9.$i.sgml)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;272
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;206
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;174
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;115
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;16&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The last number is so low relative to the rest because 9.4 is still under development. Rest assured Tom’s contributions have not slowed down! :) Thanks to Github for providing such a useful service for so many open source projects, and for providing the raw text to allow useful hacks like this.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Changing Postgres pg_dump warnings into errors with sed</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/10/postgres-sed-pgdump-warnings/"/>
      <id>https://www.endpointdev.com/blog/2013/10/postgres-sed-pgdump-warnings/</id>
      <published>2013-10-28T00:00:00+00:00</published>
      <author>
        <name>Greg Sabino Mullane</name>
      </author>
      <content type="html">
        &lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2013/10/postgres-sed-pgdump-warnings/image-0-big.png&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/10/postgres-sed-pgdump-warnings/image-0.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Turning off warnings when loading a PostgreSQL data dump can be a trickier
task than it may first appear. One of the goals of a program I was working on
was to automatically load the schema of a production database into a
development system. The program needed to stay as quiet as possible -
the users running it did not need to be distracted by annoying messages
generated by Postgres as the schema was loaded.&lt;/p&gt;
&lt;p&gt;The problem occurred when a text-based dump of the database (created
via
&lt;a href=&#34;https://www.postgresql.org/docs/current/static/app-pgdump.html&#34;&gt;pg_dump&lt;/a&gt; with the &lt;strong&gt;&amp;ndash;schema-only&lt;/strong&gt; flag) was loaded into an existing
database with the help of the the
&lt;a href=&#34;https://www.postgresql.org/docs/current/static/app-psql.html&#34;&gt;psql program&lt;/a&gt;. To load the file “test.sql” into the database
&lt;strong&gt;wilber&lt;/strong&gt;, one usually does:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql wilber -U postgres -f test.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are two general classes of “noise” that are generated by such
an action. I’ll show how to make both kinds quiet.&lt;/p&gt;
&lt;p&gt;The first problem is that psql by default is very verbose and every single
command gives an echoing confirmation of what just occurred. Thus, a typical
schema load outputs a lot of things like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql wilber -U postgres -f test.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CREATE EXTENSION
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COMMENT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CREATE TABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ALTER TABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ALTER TABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CREATE SEQUENCE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These types of messages are easy to turn off. Simply add the &lt;strong&gt;&amp;ndash;quiet&lt;/strong&gt; flag
when calling psql, usually abbreviated to just &lt;strong&gt;-q&lt;/strong&gt;, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql wilber -q -U postgres -f test.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The other type of unwanted output that can appear are the various messages from Postgres
itself. These have different &lt;em&gt;levels&lt;/em&gt; of severity: which ones are shown to you are
determined by the
&lt;a href=&#34;https://www.postgresql.org/docs/current/static/runtime-config-logging.html&#34;&gt;client_min_messages&lt;/a&gt; setting. From least important to most important, the levels are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DEBUG&lt;/li&gt;
&lt;li&gt;LOG&lt;/li&gt;
&lt;li&gt;NOTICE&lt;/li&gt;
&lt;li&gt;WARNING&lt;/li&gt;
&lt;li&gt;ERROR&lt;/li&gt;
&lt;li&gt;FATAL&lt;/li&gt;
&lt;li&gt;PANIC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The output I was seeing looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;psql:test.sql:22716: WARNING:  =&amp;gt; is deprecated as an operator name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DETAIL:  This name may be disallowed altogether in future versions of PostgreSQL.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not something I wanted users to see every time they ran the script! The solution
was to set client_min_messages to something higher than WARNING. In this case,
ERROR is a good choice. All warning-level notices will be suppressed. The SQL
would look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET client_min_messages = ERROR;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, because we are loading a file, there is no easy way to enter in SQL
commands before the file is loaded. Luckily, there is a very-poorly-documented
trick that can apply some settings before a program (such as psql) is run. Just set
the &lt;strong&gt;PGOPTIONS&lt;/strong&gt; environment variable. It allows you to pass certain options to psql
and other programs. For the case at hand, you would do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ PGOPTIONS=&amp;#39;--client-min-messages=error&amp;#39; psql wilber -q -U postgres -f test.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will ensure that client_min_messages is set to ERROR before psql
starts to load the file. If you are using a Perl script (as I was), you can
set the environment variable before making a system call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ENV{PGOPTIONS} = &amp;#39;--client-min-messages=error&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$COM = &amp;#39;psql wilber -q -U postgres -f test.sql&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;system $COM;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, if your file is from a pg_dump, you will find that this trick does not work!
Why? When pg_dump creates a file, it adds some SET commands to the top of it. One of
those is client_min_messages, which will clobber whatever you have set it to. D’oh!
Here’s what pg_dump currently sticks at the top of its output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pg_dump --schema-only | head -20 | grep -n &amp;#39;^SET&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5:SET statement_timeout = 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6:SET client_encoding = &amp;#39;UTF8&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7:SET standard_conforming_strings = on;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8:SET check_function_bodies = false;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9:SET client_min_messages = warning;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What to do? The schema file was very large, so editing it was not an option—​and
certainly not for this automated task. The answer was to modify the large
schema text file before loading it. While perl is my goto tool for most things,
this looked the perfect job for the sed program. So, in my script, I simply added this right
before psql is invoked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $COM = &amp;#34;sed --in-place &amp;#39;1,/client_min_messages/ {s/warning/ERROR/}&amp;#39; test.sql&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  system $COM;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The short explanation is that it replaces the ‘warning’ on line 9 of the file
with the word ‘error’. This prevented any of the annoying warnings from showing
up, and made the script nice and quietly happy again.&lt;/p&gt;
&lt;p&gt;The long explanation about how it works is the rest of this post. :)&lt;/p&gt;
&lt;p&gt;The sed program is a “stream editor” designed to quickly transform text. The man page
is not very useful: I recommend learning more about sed via an online tutorial.
&lt;a href=&#34;http://www.grymoire.com/Unix/Sed.html&#34;&gt;This one&lt;/a&gt; is my favorite, not least
because of the “modem noise” joke (kids, look that one up).&lt;/p&gt;
&lt;p&gt;First we instruct sed, via the &lt;strong&gt;&amp;ndash;in-place&lt;/strong&gt; flag to make the changes directly
to the file itself, rather than sending output to stdout. This is usually
abbreviated to simply &lt;strong&gt;-i&lt;/strong&gt;, but I consider the longer form more polite, as it’s
a little less obtuse to someone not familiar with the flags. Consider it a
cheap way to comment your code.&lt;/p&gt;
&lt;p&gt;After that, in single quotes, is the actual instructions we pass to sed. Finally,
we give it the file to perform the work on. Again, the instructions to sed were:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39;1,/client_min_messages/ {s/warning/ERROR/}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This has two sections: what to do, and where to do it. By default, sed operates
on every line of the file. As we only want sed to change the first occurrence
of client_min_messages, we tell it to limit its actions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1,/client_min_messages/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can instruct sed to operate on a range of lines by using the X,Y format,
aka start,stop. A lone number represents a line number in the file; in this
case we want to start at the first line of the file. You can also provide a
regular expression. In this case, we want to stop processing when we find a
line that matches the regular expression /client_min_messages/. Note that these
limits are inclusive, so that we still process the matched line.&lt;/p&gt;
&lt;p&gt;The next section tells sed what to do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39; {s/warning/ERROR/}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that both the extra space and the braces are not needed, but are there simply
to make things easier to read. You can also change the delimiter, which can
arguably help as well; here is an equivalent version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39;1,/client_min_messages/ {s:warning:ERROR:}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are telling sed to make a simple substitution of the word &lt;strong&gt;warning&lt;/strong&gt; with
the word &lt;strong&gt;ERROR&lt;/strong&gt;. I used uppercase here to make it more obvious to anyone
viewing the file that a change had been made (Postgres does not care what
the case is).&lt;/p&gt;
&lt;p&gt;Normally, this might be considered a fairly sloppy regex, as it doesn’t
match very strictly—​any lines up to and including the client_min_messages
will have the word warning replaced. However, because we can be confident
that the pg_dump output is going to remain very standard, we can let it slide.
A more proper solution might be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39;1,/client_min_messages/ {s:client_min_messages = warning:client_min_messages = ERROR:}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why didn’t I simply replace the regex and be done, like this?:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#39;s/client_min_messages = warning/client_min_messages = ERROR/&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Two reasons. First, by setting a range, we ensure that we only make the change
at the top of the file, and not anywhere else where it may be set (not by pg_dump
itself, but perhaps as the text inside a function. You never know). This is also
more efficient, as sed doesn’t need to scan the lines for a potential replacement
after it hits the first occurrence at line 9.&lt;/p&gt;
&lt;p&gt;The second reason is that we can now safely run this against the file more than once,
and not worry about a bad replacement or about losing efficiency. If we search for the
‘warning’ version of the regex, then the second time through we may end up scanning the
entire file (and any substitutions we do make will be in the wrong place).&lt;/p&gt;
&lt;p&gt;To recap, the winning lines in Perl were:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$COM = &amp;#34;sed --in-place &amp;#39;1,/client_min_messages/ {s/warning/error/}&amp;#39; test.sql&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;system $COM;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once we have this, we no longer need the PGOPTIONS setting. Which was a little dangerous
as a global $ENV inside the perl script anyways, as the setting persists even after the
first system call! So sed has saved the day, or at least made the users of this
program happier!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Making use of a Unix Pipe</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/06/making-use-of-unix-pipe/"/>
      <id>https://www.endpointdev.com/blog/2013/06/making-use-of-unix-pipe/</id>
      <published>2013-06-13T00:00:00+00:00</published>
      <author>
        <name>Mike Farmer</name>
      </author>
      <content type="html">
        &lt;p&gt;Developing in a Unix-based environment has many wonderful advantages. Thanks to &lt;a href=&#34;https://www.destroyallsoftware.com/screencasts/catalog/running-tests-asynchronously&#34;&gt;Gary Bernhardt of DestroyAllSoftware Screencasts&lt;/a&gt;, I’ve recently discovered a new use for the Unix pipe. A pipe in Unix does exactly what you might think it would do by its name. Send something in one side and watch it come out the other. If you’ve done much in the shell, you’ve probably used pipes before where you’ve probably piped some output from one command to another. Here’s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat foo.txt | grep bar&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command simply says take the output of cat and sends it to the input of grep. Pipes used in this way can yield very powerful commands in the shell.&lt;/p&gt;
&lt;p&gt;There is another pipe in Unix and this is a &lt;a href=&#34;https://en.wikipedia.org/wiki/Named_pipe&#34;&gt;named pipe&lt;/a&gt;. A named pipe, or a &lt;a href=&#34;https://linux.die.net/man/1/mkfifo&#34;&gt;FIFO&lt;/a&gt; (&lt;a href=&#34;https://en.wikipedia.org/wiki/FIFO&#34;&gt;First In, First Out&lt;/a&gt;), works similarly to command line pipe. You put stuff in one end and it comes out the other. To create a named pipe, you use the mkfifo command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkfifo my_fifo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -l
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prw-rw-r--  1 mikefarmer mikefarmer      0 Jun  5 21:22 my_fifo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice the “p” at the beginning of the file list. The “p” designates this file as a named pipe to the system. To try out our pipe, we will, in one terminal, listen for anything coming out of the pipe. Then in another terminal we will send some text to the pipe. To listen to the pipe we will be using cat to just display whatever comes into the pipe.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat my_fifo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice that when this runs, it blocks while it waits for something to come through the pipe. Now let’s push some text through the pipe. In another terminal window, I’ll just echo some text to the pipe.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &amp;#34;hello world&amp;#34; &amp;gt; my_fifo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As soon as I press enter on this command, I see that the other terminal outputs “hello world” and then exits.&lt;/p&gt;
&lt;p&gt;Now that we have a basic understanding of how the pipe works, we can set it up to run some commands. I’m going to throw my listener into a shell script that will create our pipe and start listening to and executing anything that comes out of it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;# setup_listener.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; [ ! -p commands ]; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mkfifo commands
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt; true; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sh -c &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;clear &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;cat commands&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first three lines create the pipe. The last three lines setup the listener. Remember how the process ended after the first command was sent? Well, putting this into a loop allows us to call cat repeatedly. I also added a clear call to clear my screen between each command. Now to test it out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sh ./setup_listener.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In another terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &amp;#39;ls -l&amp;#39; &amp;gt; commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You’ll notice that the command clears the screen in the other terminal and displays the output of the command ls -l. Nice!&lt;/p&gt;
&lt;p&gt;Now let’s put this to some practical use. I have a Rails application that has some &lt;a href=&#34;https://www.rubydoc.info/gems/minitest/5.0.4/frames&#34;&gt;Minitest&lt;/a&gt; tests and a small script that I’ve put together to run all the tests. Here’s the content of of my test runner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# run_all_tests.rb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d70&#34;&gt;$:&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;&amp;lt;&amp;#39;test&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;files = &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Dir&lt;/span&gt;.glob(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;test/**/*_test.rb&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;files.each{|file| &lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; file.sub(&lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/^test\/|.rb$/&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;)}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The script is a simple Ruby script that adds the test directory to the LOAD_PATH and then just requires all the files in the test directory that start with “test”. I make this script executable using a chmod +x command. Then to run it, I just call&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./run_all_tests.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Simple. To run individual tests, I just run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ minitest test/test_foo.rb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With these two commands in mind, I can now put together everything I need for my pipe. First I’m going to vertically split my screen (You can use tmux, or whatever tool you’d like. I like iTerm’s simple split screen for this.) In my terminal on the right, I’m going to startup my listener just like I did above. In the terminal on the right, I’m going to start up vim and bring up my test file. To execute my test, I’ll just use vim’s :! command to execute the test command in the shell using the % as a placeholder for the current file name in my active buffer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:!echo &amp;#34;minitest %&amp;#34; &amp;gt; commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If I’ve done everything right, my test will run on the terminal on the right and then wait for my next command. W00T! Now I’m going to run all my tests:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:!echo &amp;#34;./run_all_tests.rb&amp;#34; &amp;gt; commands&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Immediately upon pressing enter, all my tests are running on the right pane! Hooray!&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2013/06/making-use-of-unix-pipe/image-0.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/06/making-use-of-unix-pipe/image-0.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To make things a little easier in vim, I setup some key mappings for running the tests.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:nmap &amp;lt;leader&amp;gt;g :w\|:silent !echo &amp;#34;minitest %&amp;#34; &amp;gt; commands&amp;lt;cr&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:nmap &amp;lt;leader&amp;gt;G :w\|:silent !echo &amp;#34;./run_all_tests.rb&amp;#34; &amp;gt; commands&amp;lt;cr&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now I don’t necessarily want these shortcuts all the time so I’m going to add these shortcuts to a file called setup_test_shortcuts.vim. Then to activate them I just run :source setup_test_shortcuts.vim. Now I have a simple shortcut in vim for running my tests!&lt;/p&gt;
&lt;p&gt;If you are using &lt;a href=&#34;https://github.com/burke/zeus&#34;&gt;zeus&lt;/a&gt; then you will need to modify your shortcuts to look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmap &amp;lt;leader&amp;gt;g :w\|:silent !echo &amp;#34;zeus test %&amp;#34; &amp;gt; commands&amp;lt;cr&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nmap &amp;lt;leader&amp;gt;G :w\|:silent !echo &amp;#34;zeus test ./run_all_tests.rb&amp;#34; &amp;gt; commands&amp;lt;cr&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using Unix to help me in my workflow always brings a big smile to my face as I see the gains in productivity. Simple Unix concepts continue to blow my mind at their practicality and underlying simplicity.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Adventures with using Ruby 2.0 and libreadline</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/05/adventures-with-using-ruby-20-and/"/>
      <id>https://www.endpointdev.com/blog/2013/05/adventures-with-using-ruby-20-and/</id>
      <published>2013-05-17T00:00:00+00:00</published>
      <author>
        <name>Kamil Ciemniewski</name>
      </author>
      <content type="html">
        &lt;p&gt;I was asked to develop a prototype app for one of our clients lately. The basis for this app was an old Rails app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rails 3.2.8&lt;/li&gt;
&lt;li&gt;RailsAdmin&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;rbenv + ruby-build&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wanted to upgrade the stack to work with latest toys all cool kids are so thrilled about. I also didn’t have Rails console facility at my disposal since the Ruby version installed on the development machine hadn’t been compiled against libreadline.&lt;/p&gt;
&lt;p&gt;Not having root or sudo access on the machine I embarked on a sligthly hacky journey to make myself a better working environment.&lt;/p&gt;
&lt;h3 id=&#34;ruby-20&#34;&gt;Ruby 2.0&lt;/h3&gt;
&lt;p&gt;After reading Mike Farmer’s &lt;a href=&#34;/blog/2013/04/today-first-speaker-at-mwrc-is-one-and/&#34;&gt;blog post&lt;/a&gt; about Ruby 2.0 and tons of other material about it on the Internet, I wanted to get a feeling of how faster &amp;amp; greater the new Ruby is. It’s always great also to stay up-to-date with latest technologies. It’s great for me as a developer, and more importantly—​it’s great for our clients.&lt;/p&gt;
&lt;h3 id=&#34;importance-of-libreadline-in-development-with-ruby&#34;&gt;Importance of libreadline in development with Ruby&lt;/h3&gt;
&lt;p&gt;To be productive developing any Rails-based application, we have to have Rails-console available at any moment. It serves a multitude of purposes. It’s also a great scratch-pad when developing methods.&lt;/p&gt;
&lt;p&gt;While you don’t need your Ruby to support libreadline for basic uses of &lt;strong&gt;irb&lt;/strong&gt;, you need it when using with Rails.&lt;/p&gt;
&lt;h3 id=&#34;installing-ruby-200-with-rbenv-ruby-build&#34;&gt;Installing Ruby 2.0.0 with rbenv (ruby-build)&lt;/h3&gt;
&lt;p&gt;If you’ve installed ruby-build some time ago, chances are that you need to update it in order to be able to install latest build of Ruby 2.0.0&lt;/p&gt;
&lt;p&gt;To do it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; ~/.rbenv/plugins/ruby-build
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git pull&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And you should be able now to have available latest Ruby build to install:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rbenv install 2.0.0-p195&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want to install Ruby compiled with support for libreadline, you have to have it installed in your system &lt;strong&gt;before&lt;/strong&gt; compiling the build with &lt;em&gt;rbenv install&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you have access to root or sudo on your system, the easiest way is to e. g:&lt;/p&gt;
&lt;p&gt;on Debian-related Linuxes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt-get install libreadline-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or on Fedora:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum install readline-devel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;installing-libreadline-from-sources&#34;&gt;Installing libreadline from sources&lt;/h3&gt;
&lt;p&gt;In my case—​I had to download sources and compile them myself. Luckily the system had all needed essential packages installed for building it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ftp://ftp.cwru.edu/pub/bash/readline-6.2.tar.gz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar xvf readline-6.2.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; readline-6.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./configure --prefix=/home/kamil/libs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had to specify &lt;em&gt;–prefix&lt;/em&gt; option pointing at the path where I wanted the libreadline library to be installed after compilation.&lt;/p&gt;
&lt;p&gt;Then, I was able to actually build Ruby with readline support “on”:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;CONFIGURE_OPTS&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;--with-readline-dir=/home/kamil/libs&amp;#34;&lt;/span&gt; rbenv install 2.0.0-p195&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notice:&lt;/strong&gt; I was making myself a development environment and compiling from sources was my last resort. It is &lt;strong&gt;not&lt;/strong&gt; a good practice for production environments.&lt;/p&gt;
&lt;p&gt;Last thing I needed to do was to get rb-readline working with the project I was working on.&lt;/p&gt;
&lt;p&gt;It turnes out that latest rb-readline doesn’t play well with latest Ruby. Also, when using Ruby 2.0.0 one have to explicitely specify it in the Gemfile, or else it won’t be loaded for the console.&lt;/p&gt;
&lt;p&gt;Gemfile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;rb-readline&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;~&amp;gt; 0.4.2&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;this-still-isnt-perfect&#34;&gt;This still isn’t perfect&lt;/h3&gt;
&lt;p&gt;While this setup works, it won’t let you use arrow keys. The irb process crashes quickly after even first try to navigate through the text.&lt;/p&gt;
&lt;p&gt;For some reason, after upgrading Ruby, the RailsAdmin stylesheets stopped working. I noticed that they are being served with comments which should be replaced by other stylesheets like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;*= require_self
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;*= require_tree .
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I had to update Rails version in the Gemfile to have my admin back:&lt;/p&gt;
&lt;p&gt;Gemfile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;rails&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;3.2.13&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Console:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bundle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Last thing I wanted to do, was to try if I could upgrade Rails even further and have a working Rails4 setup. This was impossible unfortunately since RailsAdmin isn’t yet compatible with it &lt;a href=&#34;https://github.com/sferik/rails_admin/issues/1443&#34;&gt;as stated here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I conclude that latest Ruby is quite usable right now. If you don’t mind the quirks with the readline—​you’re pretty safe to upgrade. This assumes though that your app doesn’t use any incompatible elements.&lt;/p&gt;
&lt;p&gt;The main Ruby site describes them like so:&lt;/p&gt;
&lt;p&gt;There are five notable incompatibilities we know of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The default encoding for ruby scripts is now UTF-8 [&lt;a href=&#34;https://bugs.ruby-lang.org/issues/6679&#34;&gt;#6679&lt;/a&gt;]. Some people report that it affects existing programs, such as some benchmark programs becoming very slow [ruby-dev:46547].&lt;/li&gt;
&lt;li&gt;Iconv was removed, which had already been deprecated when M17N was introduced in ruby 1.9. Use String#encode, etc. instead.&lt;/li&gt;
&lt;li&gt;There is ABI breakage [ruby-core:48984]. We think that normal users can/should just reinstall extension libraries. You should be aware: DO NOT COPY .so OR .bundle FILES FROM 1.9.&lt;/li&gt;
&lt;li&gt;#lines, #chars, #codepoints, #bytes now returns an Array instead of an Enumerator [&lt;a href=&#34;https://bugs.ruby-lang.org/issues/6670&#34;&gt;#6670&lt;/a&gt;]. This change allows you to avoid the common idiom “lines.to_a”. Use #each_line, etc. to get an Enumerator.&lt;/li&gt;
&lt;li&gt;Object#inspect does always return a string like &lt;code&gt;#&amp;lt;ClassName:0x…&amp;gt;&lt;/code&gt; instead of delegating to #to_s. [&lt;a href=&#34;https://bugs.ruby-lang.org/issues/2152&#34;&gt;#2152&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;There are some comparatively small incompatibilities. [ruby-core:49119]&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Camp tools</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/01/camp-tools/"/>
      <id>https://www.endpointdev.com/blog/2013/01/camp-tools/</id>
      <published>2013-01-14T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;a href=&#34;http://www.devcamps.org/&#34;&gt;Devcamps&lt;/a&gt; are such a big part of my everyday work that I can’t imagine life without them. Over the years, I developed some short-cuts in navigating camps that I also can’t live without: I share them below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function camp_top() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  if [ -n &amp;#34;$1&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      cd ~/camp${1}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  elif [[ $(pwd) =~ &amp;#39;camp&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      until [[ $(basename $(pwd)) =~ &amp;#39;^camp[[:digit:]]+&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      do
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          if [[ $(pwd) =~ &amp;#39;camp&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          else
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              break
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          fi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias ct=&amp;#39;camp_top; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function cat_root() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  camp_top $*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd catalogs/* &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias cr=&amp;#39;cat_root; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function pages_root() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cat_root $*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd pages &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias pr=&amp;#39;pages_root; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function what_camp() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  c=$( camp_top $* 2&amp;gt; /dev/null; basename $( pwd ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo $c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(“cat_root” and “pages_root” are very &lt;a href=&#34;http://www.icdevgroup.org/i/dev&#34;&gt;Interchange&lt;/a&gt;-specific; you may find other short-cuts more useful in your particular camp.)&lt;/p&gt;
&lt;p&gt;There’s nothing terribly ground-breaking here, but if bash is not your native shell-tongue, then you might find these useful.&lt;/p&gt;
&lt;p&gt;What I do is to stash these somewhere like “$HOME/.bash_camps”, then alter my .bashrc:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Source campy definitions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;if [ -f ~/.bash_camps ]; then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; . ~/.bash_camps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s all it takes. Have you a camp-y shell script, function, or alias? Please share in the comments!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Simple bash shell script for running batch MySQL jobs</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/10/simple-bash-shell-script-for-running/"/>
      <id>https://www.endpointdev.com/blog/2012/10/simple-bash-shell-script-for-running/</id>
      <published>2012-10-16T00:00:00+00:00</published>
      <author>
        <name>Barrett Griffith</name>
      </author>
      <content type="html">
        &lt;p&gt;The other day I needed to run a simple mysql job to backup and delete some database records on a live server. Being a live server, it is important to make sure you aren&amp;rsquo;t asking the database to take on jobs that could potentially lock it up. Better to run a batch job. Running a batch is simple. You can call it right from the mysql console with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;source&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;[path_to]/[the_batch_script].&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;sql&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But what if there are millions of records that need deleting? &lt;strong&gt;Bash shell script to the rescue.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is the idea of the SQL job that needed to get run a few times:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;START&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TRANSACTION&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Find what you want to delete and put a LIMIT on your batch size */&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TEMPORARY&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;records_to_delete_temp&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;.....&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;limit&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1000&lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Creating backup table to archive spam orders */&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;IF&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;NOT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;EXISTS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_backup`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;LIKE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records`;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;INSERT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;INTO&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_backup`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;*&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;select&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_to_delete_temp`);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Delete Dependents - If your records have foreign key dependencies, delete them first */&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;DELETE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`dependent_1`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;record_id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;select&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_to_delete_temp`);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;DELETE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`dependent_2`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;record_id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;select&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_to_delete_temp`);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Delete the records */&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;DELETE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;select&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records_to_delete_temp`);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* Return count of remaining records - the where clause should be the same as the original select for the records to delete */&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;COUNT&lt;/span&gt;(*)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;from&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;`records`&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;where&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;....&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;COMMIT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;COUNT&lt;/span&gt;(*)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will return the remaining record count to the shell script.&lt;/p&gt;
&lt;p&gt;And the shell script&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;ret&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;mysql -u [user] -p[password] --skip-column-names [database_name]  &amp;lt; [the_batch_script].sql&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;while&lt;/span&gt; [ &lt;span style=&#34;color:#369&#34;&gt;$ret&lt;/span&gt; -gt &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rows left: &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$ret&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sleep &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#369&#34;&gt;ret&lt;/span&gt;=&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;$(&lt;/span&gt;mysql -u [user] -p[password] --skip-column-names [database_name]  &amp;lt; [the_batch_script].sql&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--skip-column-names&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the little nugget that gives you clean output from the mysql script. Without &amp;ndash;skip-column-names you will have to get more creative with parsing the returned table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-p[password]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Just a friendly reminder, no space after the -p option.&lt;/p&gt;
&lt;p&gt;Should you really be running batches to remove millions of records from a live server with a shell script?&lt;/p&gt;
&lt;p&gt;Just because you can doesn&amp;rsquo;t mean you should. Before pulling the trigger, back up, consider what could go wrong, have a plan in place to address the possible failure.&lt;/p&gt;
&lt;p&gt;Find something fun for your hands to do while bash takes care of running the jobs. At the least, cross your fingers!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>File test comparison table for shell, Perl, Ruby, and Python</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2009/08/file-test-comparison-table-for-shell/"/>
      <id>https://www.endpointdev.com/blog/2009/08/file-test-comparison-table-for-shell/</id>
      <published>2009-08-31T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;A few days ago, my co-worker Richard asked how in Python you would do the -x Bourne shell and Perl file test that checks whether a file is executable. This is (for me, at least) a really commonly used function but one I hadn’t needed to do yet in Python, so I looked it up.&lt;/p&gt;
&lt;p&gt;That wasn’t so hard to find, but then I wondered about the other shell and Perl file tests that I use all the time. Finding equivalents for those was harder than I expected. A web search didn’t turn much up aside from language holy wars and limited answers, but I didn’t find any exhaustive list.&lt;/p&gt;
&lt;p&gt;So I made my own. Below is a table comparing file test operators in the original Bourne shell-compatibles bash, ksh, and zsh; Perl’s expanded set; Ruby’s which was derived first from Perl; and equivalent Python code.&lt;/p&gt;
&lt;p&gt;There are still some blanks where I didn’t find a good equivalent. Of course I’m sure it’s possible with enough custom logic to achieve the same end, but I have tried to stick with relatively simple formulations using built-in functions for now. I’ll be happy to fill in the blanks if any readers make suggestions.&lt;/p&gt;
&lt;p&gt;Performance notes on avoiding multiple stats of the same file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Starting with Perl 5.9.1, file tests can be “stacked” and will use a single stat for all tests, e.g. -f -x file. In older versions of Perl you can do -f file &amp;amp;&amp;amp; -x _ instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ruby’s File::Stat class can be used to cache a stat for multiple tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Python’s os.stat(file).st_mode can be stored and used for multiple tests.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unless otherwise specified, these tests follow symbolic links and operate on the target of the link, rather than the link itself.&lt;/p&gt;
&lt;p&gt;All tests return boolean true or false unless otherwise noted.&lt;/p&gt;
&lt;style&gt;
tr { background: #f1f1f1 !important; }
&lt;/style&gt;
&lt;div class=&#34;table-scroll&#34;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;bash/ksh/zsh&lt;/th&gt;
&lt;th&gt;Perl&lt;/th&gt;
&lt;th&gt;Ruby&lt;/th&gt;
&lt;th&gt;Python&lt;/th&gt;
&lt;/tr&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is readable by effective uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-r &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?r, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.R_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.readable?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is writable by effective uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-w &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?w, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.W_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.writable?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is executable by effective uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-x &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?x, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.X_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.executable?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is owned by effective uid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-O file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-o &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?o, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_uid == os.geteuid()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.owned?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is owned by the effective gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-G file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;(stat(&#39;file&#39;))[5] == $)&lt;/td&gt;
&lt;td&gt;test ?G, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_gid == os.getegid()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.grpowned?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is readable by real uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-r file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-R &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?R, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.R_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.readable_real?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is writable by real uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-w file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-W &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?W, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.W_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.writable_real?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is executable by real uid/gid&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-x file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-X &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?X, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.access(&#39;file&#39;, os.X_OK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.executable_real?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File is owned by real uid&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-O &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?O, &#39;file&#39;&lt;/td&gt;
&lt;td&gt;os.stat(&#39;file&#39;).st_uid == os.getuid()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File exists&lt;/td&gt;
&lt;td&gt;-e file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-e &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?e, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.path.exists(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-a file&lt;/td&gt;
&lt;td&gt;File.exist?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File has zero size (is empty)&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-f file -a ! -s file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-z &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?z, &#39;file&#39;&lt;/td&gt;
&lt;td&gt;os.path.getsize(&#39;file&#39;) == 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.zero?(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;os.stat(&#39;file&#39;).st_size == 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File exists and has size greater than zero&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-s file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-s &#39;file&#39; &lt;em&gt;(boolean and returns size in bytes)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;test ?s, &#39;file&#39; &lt;em&gt;(boolean: returns nil if doesn&#39;t exist or has zero size, size of the file otherwise)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;os.path.getsize(&#39;file&#39;) &gt; 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.size?(&#39;file&#39;) &lt;em&gt;(same)&lt;/em&gt;&lt;br/&gt;
&lt;/td&gt;&lt;td&gt;os.stat(&#39;file&#39;).st_size &gt; 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File exists, return size in bytes&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-s &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;File.size(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;os.path.getsize(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;os.stat(&#39;file&#39;).st_size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a plain file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-f file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-f &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?f, &#39;file&#39;&lt;/td&gt;
&lt;td&gt;os.path.isfile(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.file?(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;stat.S_ISREG(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a directory&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-d file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-d &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?d, &#39;file&#39;&lt;/td&gt;
&lt;td&gt;os.path.isdir(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.directory?(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;stat.S_ISDIR(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a symbolic link&lt;/td&gt;
&lt;td&gt;-h file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-l &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?l, &#39;file&#39;&lt;/td&gt;
&lt;td&gt;os.path.islink(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-L file&lt;/td&gt;
&lt;td&gt;File.symlink?(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;stat.S_ISLNK(os.lstat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a named pipe (FIFO)&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-p file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-p &#39;file&#39; &lt;em&gt;(can also be used on a filehandle)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;test ?p, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;stat.S_ISFIFO(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.pipe?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a socket&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-S file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-S &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?S, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;stat.S_ISSOCK(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.socket?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a block special file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-b file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-b &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?b, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;stat.S_ISBLK(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.blockdev?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File is a character special file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-c file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-c &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?c, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;stat.S_ISCHR(os.stat(&#39;file&#39;).st_mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.chardev?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File type (returns string &#39;file&#39;, &#39;directory&#39;, &#39;characterSpecial&#39;, &#39;blockSpecial&#39;, &#39;fifo&#39;, &#39;link&#39;, &#39;socket&#39;, or &#39;unknown&#39;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;File.ftype(&#39;file&#39;)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;Filehandle or descriptor is opened to a tty&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-t fd&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-t $fh&lt;/td&gt;
&lt;td&gt;fd.isatty&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.isatty(fd)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fd.tty?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File has setuid bit set&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-u file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-u &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?u, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_mode &amp; stat.S_ISUID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.setuid?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File has setgid bit set&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-g file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-g &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?g, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_mode &amp; stat.S_ISGID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.setgid?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File has sticky bit set&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-k file&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;-k &#39;file&#39;&lt;/td&gt;
&lt;td&gt;test ?k, &#39;file&#39;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_mode &amp; stat.S_ISVTX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File.sticky?(&#39;file&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File is an ASCII text file (heuristic guess)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-T &#39;file&#39;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File is a &#34;binary&#34; file (opposite of -T)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-B &#39;file&#39;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File modification time&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td&gt;(stat(&#39;file&#39;))[9]&lt;/td&gt;
&lt;td&gt;test ?M, &#39;file&#39; &lt;em&gt;(returns Time object)&lt;/em&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_mtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-M &#39;file&#39; &lt;em&gt;(script start time minus file modification time, in days)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;File.mtime(&#39;file&#39;) &lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;File access time&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td&gt;(stat(&#39;file&#39;))[8]&lt;/td&gt;
&lt;td&gt;test ?A, &#39;file&#39; &lt;em&gt;(returns Time object)&lt;/em&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_atime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-A &#39;file&#39; &lt;em&gt;(script start time minus file access time, in days)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;File.atime(&#39;file&#39;) &lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&#34;2&#34;&gt;Inode change time (Unix)&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;&lt;/td&gt;
&lt;td&gt;(stat(&#39;file&#39;))[10]&lt;/td&gt;
&lt;td&gt;test ?C, &#39;file&#39; &lt;em&gt;(returns Time object)&lt;/em&gt;&lt;/td&gt;
&lt;td rowspan=&#34;2&#34;&gt;os.stat(&#39;file&#39;).st_ctime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-C &#39;file&#39; &lt;em&gt;(script start time minus inode change time, in days)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;File.ctime(&#39;file&#39;) &lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File has been modified since it was last read&lt;/td&gt;
&lt;td&gt;-N file&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not&lt;/td&gt;
&lt;td&gt;file1 -nt file2&lt;/td&gt;
&lt;td&gt;(stat(&#39;file1&#39;))[9] &gt; (stat(&#39;file2&#39;))[9]&lt;/td&gt;
&lt;td&gt;test ?&gt;, &#39;file1&#39;, &#39;file2&#39;&lt;/td&gt;
&lt;td&gt;os.path.exists(&#39;file1&#39;) and (not os.path.exists(&#39;file2&#39;) or os.stat(&#39;file1&#39;).st_mtime &gt; os.stat(&#39;file2&#39;).st_mtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file1 is older than file2, or if file2 exists and file1 does not&lt;/td&gt;
&lt;td&gt;file1 -ot file2&lt;/td&gt;
&lt;td&gt;(stat(&#39;file1&#39;))[9] &lt; (stat(&#39;file2&#39;))[9]&lt;/td&gt;
&lt;td&gt;test ?&lt;, &#39;file1&#39;, &#39;file2&#39;&lt;/td&gt;
&lt;td&gt;os.path.exists(&#39;file2&#39;) and (not os.path.exists(&#39;file1&#39;) or os.stat(&#39;file1&#39;).st_mtime &lt; os.stat(&#39;file2&#39;).st_mtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file1 and file2 refer to the same device and inode numbers&lt;/td&gt;
&lt;td&gt;file1 -ef file2&lt;/td&gt;
&lt;td&gt;join(&#39;:&#39;, (stat(&#39;file1&#39;))[0,1]) eq join(&#39;:&#39;, (stat(&#39;file2&#39;))[0,1])&lt;/td&gt;
&lt;td&gt;test ?-, &#39;file1&#39;, &#39;file2&#39;&lt;/td&gt;
&lt;td&gt;os.path.samefile(&#39;file1&#39;, &#39;file2&#39;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;file1 and file2 have the same modification times&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;(stat(&#39;file1&#39;))[9] == (stat(&#39;file2&#39;))[9]&lt;/td&gt;
&lt;td&gt;test ?=, &#39;file1&#39;, &#39;file2&#39;&lt;/td&gt;
&lt;td&gt;os.stat(&#39;file1&#39;).st_mtime == os.stat(&#39;file2&#39;).st_mtime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Complete details are in the manuals for each language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bash: &lt;a href=&#34;https://linux.die.net/man/1/bash&#34;&gt;&lt;code&gt;man bash&lt;/code&gt;&lt;/a&gt; and search for “CONDITIONAL EXPRESSIONS”&lt;/li&gt;
&lt;li&gt;ksh: &lt;a href=&#34;https://linux.die.net/man/1/pdksh&#34;&gt;&lt;code&gt;man pdksh&lt;/code&gt;&lt;/a&gt; and search for “test expression”&lt;/li&gt;
&lt;li&gt;zsh: &lt;a href=&#34;https://linux.die.net/man/1/zshmisc&#34;&gt;&lt;code&gt;man zshmisc&lt;/code&gt;&lt;/a&gt; and search for “CONDITIONAL EXPRESSIONS”&lt;/li&gt;
&lt;li&gt;Perl: &lt;a href=&#34;https://perldoc.perl.org/functions/-X.html&#34;&gt;&lt;code&gt;perldoc -f -f&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://perldoc.perl.org/filetest.html&#34;&gt;filetest pragma&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ruby: &lt;a href=&#34;https://ruby-doc.org/core-2.5.1/File.html&#34;&gt;File class&lt;/a&gt; (&lt;a href=&#34;https://www.tutorialspoint.com/ruby/ruby_file_methods.htm&#34;&gt;summary version&lt;/a&gt;) and &lt;a href=&#34;https://ruby-doc.org/core-1.8.7/Kernel.html#M001085&#34;&gt;test() built-in&lt;/a&gt;, &lt;a href=&#34;https://ruby-doc.org/core-2.5.1/IO.html&#34;&gt;IO class&lt;/a&gt; docs&lt;/li&gt;
&lt;li&gt;Python: &lt;a href=&#34;https://docs.python.org/3/library/os.html#os.access&#34;&gt;os.access&lt;/a&gt;, &lt;a href=&#34;https://docs.python.org/3/library/os.html#os.stat&#34;&gt;os.stat&lt;/a&gt;, &lt;a href=&#34;https://docs.python.org/3/library/stat.html&#34;&gt;stat() results&lt;/a&gt;, &lt;a href=&#34;https://docs.python.org/3/library/os.path.html#module-os.path&#34;&gt;os.path&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
</feed>
