<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ✋</title>
    <description>The latest articles on DEV Community by ✋ (@circumlocutions).</description>
    <link>https://dev.to/circumlocutions</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2404%2Fl9MafPrh.jpeg</url>
      <title>DEV Community: ✋</title>
      <link>https://dev.to/circumlocutions</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/circumlocutions"/>
    <language>en</language>
    <item>
      <title>Iterative Development as Discovery</title>
      <dc:creator>✋</dc:creator>
      <pubDate>Thu, 26 Jan 2017 14:28:33 +0000</pubDate>
      <link>https://dev.to/circumlocutions/iterative-development-as-discovery</link>
      <guid>https://dev.to/circumlocutions/iterative-development-as-discovery</guid>
      <description>

&lt;p&gt;In a class on shell scripting, my professor asked whether pipes were better than temporary files. I don't know enough to generalize, but pipes often suit that evolving thinking-about-a-problem where you're not entirely sure what the answer is because you're still formulating and reformulating the question.&lt;/p&gt;

&lt;p&gt;Say, for example, I notice several failed SSH attempts on my server. Where are they coming from? To print the IP addresses, I might run:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But imagine that returns a long list of IP addresses, some of which are repeats because I haven't installed &lt;code&gt;fail2ban&lt;/code&gt;. So I pipe it to &lt;code&gt;sort&lt;/code&gt; to grab just the unique values.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log | sort -u
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That gives me a list without repeats. But then perhaps I wonder where these IPs are located, so I do a &lt;code&gt;whois&lt;/code&gt; lookup on each.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log | sort -u \
    | while read address; do whois "$address" \
    | grep "Country: "; done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's fine, I guess. But now I want to see the attempts per country. So I drop the &lt;code&gt;sort -u&lt;/code&gt;, and do a &lt;code&gt;whois&lt;/code&gt; lookup on every IP address, leaving in all the repeats.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log \
    | while read address; do whois "$address" \
    | grep -m 1 -i "Country: "; done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(The &lt;code&gt;grep&lt;/code&gt; arguments say “match the first instance only, case insensitive. Some &lt;code&gt;whois&lt;/code&gt; information uses a lowercase ‘c' in ‘Country'.) But the output isn't very helpful.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Country:       US 
Country:       US 
country:       JP 
country:       JP 
country:       JP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ah, I know. I'll switch the word ‘country' with the actual IP address within the &lt;code&gt;while&lt;/code&gt; loop and then pipe it to &lt;code&gt;awk&lt;/code&gt; to switch the position of the country code and IP address, perhaps even adding an ASCII arrow between them.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log \
 | while read address; do whois "$address" \
     | grep -m 1 -i "Country: " \
     | sed "s/[Cc]ountry:/$address/"; done \
 | awk '{print $2 " --&amp;gt; "$1}'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example output (with random, made-up IPs):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JP --&amp;gt; 219.47.220.30 
JP --&amp;gt; 219.47.220.30 
NL --&amp;gt; 139.47.220.30 
US --&amp;gt; 149.47.31.192
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And this is almost what I want to know, except that I want to count the number of repeated IP addresses and then rank them by number of attempts, with the higher numbers first. And I don't like that ASCII arrow, after all.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '/Failed password for/ {print $11}' /var/log/auth.log \
 | while read address; do whois "$address" \
     | grep -m 1 -i "Country: "\
     | sed "s/[Cc]ountry:/$address/"; done \
 | awk '{print $2 " " $1}' \
 | uniq -c \
 | sort -r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example output (with random, made-up IPs):&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 JP 219.47.220.30 
4 KR 59.150.234.132 
1 US 99.62.218.217 
1 US 9.41.14.160
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And at this point, I've found both the question and the answer. Ranked by number of attempts, what are the IP addresses and countries from which failed login attempts have come? Since I've answered my question, I'd write the output to a file for later analysis and processing, if any.&lt;/p&gt;

&lt;p&gt;Pipes separate the processing of data from its storage in a way analogous to how HTML and CSS separate the structure and presentation of content. In this analogy, temporary files are the inline CSS of data processing.&lt;/p&gt;

&lt;p&gt;But pipes are also useful when you're still waiting for the emergence of the question which your code answers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://medium.com/@circumlocutions/pipes-vs-temporary-files-55061a1141ad#.93y7oow4p"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;


</description>
      <category>softwaredevelopment</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
