<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Terminal Inflection</title>
	<atom:link href="http://terminalinflection.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://terminalinflection.com</link>
	<description>Linux esoterica, fixes and rants</description>
	<lastBuildDate>Fri, 10 Oct 2014 10:58:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.0.3</generator>
	<item>
		<title>Puppet iteration through recursion</title>
		<link>http://terminalinflection.com/puppet-recursion/</link>
		<comments>http://terminalinflection.com/puppet-recursion/#respond</comments>
		<pubDate>Thu, 10 Apr 2014 10:51:36 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Puppet]]></category>
		<category><![CDATA[amanda]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1961</guid>
		<description><![CDATA[One thing that the Puppet language doesn&#8217;t do &#8211; and apparently this is entirely by design &#8211; is iteration. There&#8217;s no way to loop a block &#8211; no foreach, while or repeat. While this function would seem to be a natural language construct, Puppet is about prototyping, and configuration should be specific, rather than derived. <a href='http://terminalinflection.com/puppet-recursion/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>One thing that the <a href="http://docs.puppetlabs.com/learning/variables.html">Puppet language</a> doesn&#8217;t do &#8211; and apparently this is entirely by design &#8211; is iteration. There&#8217;s no way to loop a block &#8211; no foreach, while or repeat.  While this function would seem to be a natural language construct, Puppet is about prototyping, and configuration should be specific, rather than derived.  However, there are ways of performing an iteration, should it become necessary, and this is one example.</p>
<p>This example pertains to the AMANDA backup server software. It requires a definition for a sequence of virtual tapes.  These are just empty directories that need to be created and then registered using the AMANDA &#8220;amlabel&#8221; command. All I wanted to do was to say to Puppet, &#8220;Create me n virtual disks, where n is an integer variable&#8221;. If it was a simple matter of creating an array [ 1..n ] and then passing this to a define, there wouldn&#8217;t be a problem, but there&#8217;s no way in Puppet to create a variable-length array.  One can only do something like this: </p>
<pre>$array = [ 1,2,3,4,5 ]</pre>
<p> which is no use when the number of elements is not known.</p>
<p>But one simple way to accomplish a variable length sequence is through recursion.  Consider this puppet define:</p>
<pre>
define amanda_create_slot ($backup_set, $slot_path, $slot_num ) {
  if "${slot_num}" > '0' {
    exec { "slot${slot_num}":
      creates => "${slot_path}/slot${slot_num}",
      user => "amandabackup",
      command => "/bin/mkdir $slot_path/slot${slot_num};
	/usr/sbin/amlabel $backup_set $backup_set-${slot_num} slot $slot_num"
    }
    $decrement = inline_template('<%= @slot_num.to_i - 1 %>')
    $amanda_create_slot { "slots-${decrement}": backup_set => $backup_set,
		                                slot_num => $decrement,
			                        slot_path => $slot_path }
  }	
}
</pre>
<p>It checks that the slot number passed to it is greater than zero, and if so, creates a slot with that index.  It then decrements the argument &#8220;slot_num&#8221;, and then invokes itself again.  It will continue to do this until the variable slot_num is reduced to zero, at which point the if-block will fail and the recursive loop will collapse.</p>
<p>In a manifest, this function is initially invoked like this:</p>
<pre>
amanda_create_slot { "slots": backup_set => Daily,
			      slot_num => "10",
			      slot_path => "/var/amanda/slots" }

}
</pre>
<p>The result will be a nice series of virtual tape slots, all numbered from 1 to 10.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/puppet-recursion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Schedule Icinga/Nagios Downtime with Capistrano</title>
		<link>http://terminalinflection.com/icinga-downtime-capistrano/</link>
		<comments>http://terminalinflection.com/icinga-downtime-capistrano/#respond</comments>
		<pubDate>Tue, 01 Apr 2014 15:39:46 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Monitoring]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1944</guid>
		<description><![CDATA[Capistrano is an invaluable automation tool, but simultaneously restarting services and hosts can play havoc with your monitoring and alerting. It&#8217;s therefore also a good idea to use Capistrano to control your monitoring. In this post I&#8217;m going to show how I do it with my Icinga installation. The way scheduled downtime works in Icinga <a href='http://terminalinflection.com/icinga-downtime-capistrano/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Capistrano is an invaluable automation tool, but simultaneously restarting services and hosts can play havoc with your monitoring and alerting. It&#8217;s therefore also a good idea to use Capistrano to control your monitoring.  In this post I&#8217;m going to show how I do it with my Icinga installation.</p>
<p>The way scheduled downtime works in Icinga (these instructions apply to Nagios as well) is described <a href="http://docs.icinga.org/latest/en/downtime.html">here</a>. Briefly, when downtime is scheduled for a host and/or services, then no alert notifications are sent out during the defined period.  Downtime gets scheduled with a start time, an end time, and a duration, and may be either fixed or flexible (the difference is, flexible downtime will start from the moment when a host or service goes down inside of the scheduled period).</p>
<p>Icinga offers a REST API to control it from the command line, but to be honest, it&#8217;s a little tricky to use and I can&#8217;t work out how to schedule downtime with it, rather than to just disable notifications.  So instead, I find the command-file pipe a simpler solution &#8211; it requires access to the monitoring server itself, but that&#8217;s not really a problem.</p>
<p>The Icinga command-file pipe is a special file known as a FIFO that acts as a pipe into a process, in this case, the daemon itself.  Therefore, whatever gets written to this file gets funnelled straight into the Icinga process.  It&#8217;s location can be found by checking the &#8220;command_file&#8221; option in the /etc/icinga/icinga.cfg main config file. For example:</p>
<pre>
/etc/icinga/icinga.cfg:

command_file=/var/spool/icinga/cmd/icinga.cmd
</pre>
<p>This file is owned by the icinga user, so security is controlled by permissions in that only the icinga user or a member of the icingacmd group can write to this file. For this reason, you&#8217;ll need to update /etc/sudoers to permit your Capistrano user to write to the command file as the icinga user. Something like this, using the &#8220;tee&#8221; command:</p>
<pre>
/etc/sudoers

ALL=(icinga) NOPASSWD: /usr/bin/tee -a /var/spool/icinga/cmd/icinga.cmd
</pre>
<p>Then, all that one needs to do is send a formatted string to the command pipe and Icinga will execute the instruction accordingly.  The Icinga and Nagios documentation describes the order of each semicolon-separated field.</p>
<p>Setting up a full Capistrano project is beyond the scope of this post, but assuming you have one, the files below will get things working.</p>
<p>This is a helper method to simply execute an Icinga command, for a particular host and taking one parameter, for the number of minutes of downtime. </p>
<pre>
capistrano/recipes/helpers/icinga_commands.rb:

def icinga_cli_cmd ( icingaCommand, hostName, minutes )
   run <<-CMD
      CMDFILE="/var/spool/icinga/rw/icinga.cmd";
      MINUTES=`expr #{minutes} * 60`
      NOW=`date +%s`;
      STOP=`expr $NOW + $MINUTES`;
      DURATION=$MINUTES;
      AUTHOR="Capistrano";
      COMMENT="Automation";
      CMDLINE="[$NOW] #{icingaCommand};#{hostName};$NOW;$THEN;1;0;$DURATION;$AUTHOR;$COMMENT";
      echo $CMDLINE | sudo -u icinga /usr/bin/tee -a $CMDFILE
   CMD
end
</pre>
<p>This is the Capistrano recipe to scheduled downtime for a host and all its services.</p>
<pre>
capistrano/recipes/icinga.rb:

namespace "icinga" do
  task :config do
    close_sessions
    top.load(:string => "set :user, 'deploy'")
  end

  desc "Schedule Icinga Downtime of host and all services"
  task :downtime_host_svc, :roles => :monitor do
    config
    icinga_cli_cmd "SCHEDULE_HOST_SVC_DOWNTIME", "#{hostName}", "#{period}"
  end
end
</pre>
<p>And within the host definitions themselves, you'll need something like this:</p>
<pre>
capistrano/deploy/development.rb:

role :monitor, "monitor.example.com"
</pre>
<p>Your particular setup may involve some tweaking, and this is just an example that can easily be extended to better control Icinga. To invoke this Capistrano recipe from the command line, scheduling 7 minutes of downtime on the "backup" host, execute this command:</p>
<pre>
$ cap development icinga:downtime_host_svc -s hostName=backup -s period=7
</pre>
<p>This will send a string similar to this one to the Icinga daemon, and this should also be reflected in the icinga.log file.</p>
<pre>
[1396341638] SCHEDULE_HOST_SVC_DOWNTIME;backup;1396341638;;1;0;;Capistrano;Automation
</pre>
<p>Check the effect by viewing the log file and checking the host display in the Icinga web UI.</p>
<p>I use this recipe in a Jenkins job that restores a database snapshot.  It means that while the database is being restarted I can suppress warnings. What's the point of being notified of what you already know?</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/icinga-downtime-capistrano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Randomly stagger parallel command execution</title>
		<link>http://terminalinflection.com/parallel-stagger/</link>
		<comments>http://terminalinflection.com/parallel-stagger/#respond</comments>
		<pubDate>Fri, 21 Mar 2014 10:49:12 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Quick & Dirty]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1939</guid>
		<description><![CDATA[I&#8217;m a big fan of using MultiSSH for performing quick hacks on multiple hosts at once. ClusterSSH is nice too. I hate myself for using it, because frankly any form of parallel execution should really use a formal tool, something like Capistrano, but there are times when quick and dirty is what&#8217;s required. The problem <a href='http://terminalinflection.com/parallel-stagger/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m a big fan of using <a href="http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/multissh/">MultiSSH for performing quick hacks on multiple hosts at once</A>. ClusterSSH is nice too. I hate myself for using it, because frankly any form of parallel execution should really use a formal tool, something like Capistrano, but there are times when quick and dirty is what&#8217;s required.</p>
<p>The problem is, if the parallel commands you&#8217;re executing are all hitting the same network resource at exactly the same time, you can get timeouts, failures, or possibly even look up the daemon. I&#8217;m looking at you, Puppet (sometimes &#8220;puppetd -t &#8211;splay&#8221; just doesn&#8217;t cut it).</p>
<p>What I like to do to prevent everything being too simultaneous is to precede the command with a random sleep pause, like this:</p>
<pre>
sleep $(( $RANDOM*8/1000 )); puppetd -t --noop
</pre>
<p>This will randomly sleep for any time between 1 and 8 seconds before continuing with the Puppet agent update, saving the Puppetmaster and its precious thread count.</p>
<p>This could similiarly be used during YUM or APT updates, but really, if you have to, you should probably be automating these kinds of solutions.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/parallel-stagger/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reconfigure Mongo DB Replica Set Member by Attribute</title>
		<link>http://terminalinflection.com/reconfigure-mongo-rs/</link>
		<comments>http://terminalinflection.com/reconfigure-mongo-rs/#comments</comments>
		<pubDate>Thu, 21 Nov 2013 16:30:53 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Database]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1920</guid>
		<description><![CDATA[When configuring the attributes of members of a Mongo DB replica set, either in the mongo shell or a script, the typical procedure is to set each attribute by its array reference. The weakness in this method is that it&#8217;s necessary to know what the array index is of the host whose attribute you need <a href='http://terminalinflection.com/reconfigure-mongo-rs/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>When configuring the attributes of members of a Mongo DB replica set, either in the mongo shell or a script, the typical procedure is to set each attribute by its array reference. The weakness in this method is that it&#8217;s necessary to know what the array index is of the host whose attribute you need to configure. This may not be possible for a generalized script.</p>
<pre>
cfg = rs.config();
cfg.members[1].priority = 2;
rs.reconfig(cfg);
</pre>
<p>However, with a bit of mongo javascript it&#8217;s possible to write a small function to cycle through the member config array, determine the index of a host and then set an attribute.</p>
<p>In this example, we want to configure the Mongo DB nodedb02.example.com as a hidden node.  This can be done like this:</p>
<pre>
cfg = rs.config();
cfg.members.forEach( 
	function(item, i) {
		if ( item.host == "nodedb02.example.com" ) 
		{ 
			cfg.members[i].priority = 0;
			cfg.members[i].hidden = true;
			rs.reconfig(cfg);
		}  
	} 
)
</pre>
<p>If, on the other hand, you wanted to change the slave delay on a read-only reporting node, this could be accomplished by testing each node to find which has the &#8220;hidden&#8221; attribute set to &#8220;true&#8221;:</p>
<pre>
		if ( item.hidden == "true" ) 
		{ 
			cfg.members[i].slaveDelay=0
			rs.reconfig(cfg)
		}  
</pre>
<p>Use this function in Mongo JS scripts, be it with Capistrano, Puppet or some other automation technique, and everything got just a bit more hands-off.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/reconfigure-mongo-rs/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Fast Indenting with vi</title>
		<link>http://terminalinflection.com/fast-indenting-with-vi/</link>
		<comments>http://terminalinflection.com/fast-indenting-with-vi/#respond</comments>
		<pubDate>Wed, 18 Sep 2013 14:11:46 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[how to]]></category>
		<category><![CDATA[Quick & Dirty]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1883</guid>
		<description><![CDATA[Indenting lines with leading tabs is an important technique for writing clear and readable code, and are essential in Python where they have syntactic meaning. Many IDEs insert tabs automatically, but if you&#8217;re using vi it can be tedious to insert tabs individually. Fortunately, there is an easy shortcut, and it&#8217;s a very handy command <a href='http://terminalinflection.com/fast-indenting-with-vi/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Indenting lines with leading tabs is an important technique for writing clear and readable code, and are essential in Python where they have syntactic meaning. Many IDEs insert tabs automatically, but if you&#8217;re using <code>vi</code> it can be tedious to insert tabs individually.  Fortunately, there is an easy shortcut, and it&#8217;s a very handy command to remember.</p>
<p>In the <code>vi</code> session, enter command mode by pressing <code>ESC</code>.  Then, set the size of the tabs with the following command:</p>
<pre>
  :set shiftwidth=2
</pre>
<p>To make this the default, put &#8220;set shiftwidth=2&#8221; in your ~/.exrc file.</p>
<p>Then, to tab shift the next 13 lines, you&#8217;d type a command like this:</p>
<pre>
13>>
</pre>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/fast-indenting-with-vi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Determine MongoDB secondary node without authenticating</title>
		<link>http://terminalinflection.com/determine-mongo-secondary/</link>
		<comments>http://terminalinflection.com/determine-mongo-secondary/#respond</comments>
		<pubDate>Thu, 05 Sep 2013 14:36:07 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[mongo]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1889</guid>
		<description><![CDATA[While operating a MongoDB cluster, it can often be useful in maintenance scripts to check whether a host is the primary or secondary (master or slave). This is easy to do, and can be done without having to authenticate against the database. Scripts can be made simpler as there is no need to shield the <a href='http://terminalinflection.com/determine-mongo-secondary/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>While operating a MongoDB cluster, it can often be useful in maintenance scripts to check whether a host is the primary or secondary (master or slave).  This is easy to do, and can be done without having to authenticate against the database.  Scripts can be made simpler as there is no need to shield the login credentials, as there aren&#8217;t any.</p>
<p>When one connects a Mongo database process without credentials, using the &#8220;mongo&#8221; client command, the implicit &#8220;test&#8221; database is used.  This is a default, and a kind of empty chroot database.  Even though it&#8217;s an empty database, it still has read-only access to replica information.  This can be very handy when automating deployment and monitoring scripts.</p>
<p>There are two commands in particular that are useful for determining the status of a replica set member.  These are demonstrated in the following console example, which is fairly self-explanatory. </p>
<pre>
$ mongo localhost:27017
connecting to: localhost:27017/test
> db.isMaster().secondary
false
> db.isMaster().ismaster
true
</pre>
<p>This could also be executed non-interactively like this:</p>
<pre>
mongo localhost:27017 --quiet --eval 'db.isMaster().secondary'
</pre>
<h2>Shell Script Snippet: wait for replica synchronization to finish</h2>
<p>When resynchronizing a replica set slave, it will report its status as RECOVERING until it completes, at which point it becomes SECONDARY.  The simple example below demonstrates a block of bash to test for this.  </p>
<pre>
while [ "$RESULT" != "true" ]; do
   RESULT=$(mongo localhost --quiet --eval 'db.isMaster().secondary');
   sleep 5;
done
</pre>
<p>This is over-simplified to demonstrate the logic.  In a real-world script you&#8217;d have an exit clause to prevent an endless loop in the case when the replica node <i>never</i> recovers.</p>
<p>Other useful commands can be discovered while browsing the mongo console.  Find these using commands of the format:</p>
<pre>
  db.help()
</pre>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/determine-mongo-secondary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Obtain the external IP address from the command line</title>
		<link>http://terminalinflection.com/cli-ext-ip-address/</link>
		<comments>http://terminalinflection.com/cli-ext-ip-address/#respond</comments>
		<pubDate>Tue, 30 Jul 2013 10:57:48 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Quick & Dirty]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1876</guid>
		<description><![CDATA[The IP address that a host presents to the Internet is probably not the same one on its network interface, thanks to the magic of NAT. The difficulty of obtaining this address comes from the fact that one must effectively &#8220;ask&#8221; an outside source for the answer, since the host and internal network is not <a href='http://terminalinflection.com/cli-ext-ip-address/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>The IP address that a host presents to the Internet is probably not the same one on its network interface, thanks to the magic of NAT. The difficulty of obtaining this address comes from the fact that one must effectively &#8220;ask&#8221; an outside source for the answer, since the host and internal network is not in charge of allocating this address, and therefore doesn&#8217;t know it.  Fortunately, this can be accomplished easily with a simple command line.</p>
<p>One can use wget or curl for this (this example uses wget) and the external site ipecho.net, which offers an unformatted page displaying the IP address.</p>
<pre>
   wget -q -O - http://ipecho.net/plain && echo
</pre>
<p>This expression could be executed inside a subshell and the result written to a variable.  From here, this information could be useful for checking that a VPN client is connected.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/cli-ext-ip-address/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extract all sender email addresses from a mailbox with Python</title>
		<link>http://terminalinflection.com/python-script-email/</link>
		<comments>http://terminalinflection.com/python-script-email/#comments</comments>
		<pubDate>Mon, 24 Jun 2013 10:04:42 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Quick & Dirty]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1832</guid>
		<description><![CDATA[As a freelance tech contractor, I get a lot of emails every day from recruiters about prospective jobs. Many of these are unsolicited, but this is a good thing, as over time, quite a large list of contacts can be built up. I don&#8217;t have the time to reply to each one &#8211; particularly those <a href='http://terminalinflection.com/python-script-email/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>As a freelance tech contractor, I get a lot of emails every day from recruiters about prospective jobs.  Many of these are unsolicited, but this is a good thing, as over time, quite a large list of contacts can be built up.  I don&#8217;t have the time to reply to each one &#8211; particularly those that don&#8217;t suit my skillset, or if I&#8217;m happily indentured &#8211; but I do file these emails into a separate Gmail Mailbox which I&#8217;ve labelled &#8220;Employment&#8221;.  </p>
<p>I&#8217;m not going to add each recruiter to my Contacts as it arrives &#8211; that would be time consuming to start and difficult to maintain.  But when it comes time to make a great big recruiter contact list, I&#8217;ve written the Python script below to scrap the entire mailbox and output each unique email address.</p>
<pre>
#!/usr/bin/python

import imaplib
import sys
import email
import re

#FOLDER=sys.argv[1]
FOLDER='Employment'
LOGIN='example.address@gmail.com'
PASSWORD='xxxxxxxxxxxx'
IMAP_HOST = 'imap.gmail.com'  # Change this according to your provider

email_list = []
email_unique = []

mail = imaplib.IMAP4_SSL(IMAP_HOST)
mail.login(LOGIN, PASSWORD)
mail.select(FOLDER) 

result, data = mail.search(None, 'ALL')
ids = data[0]
id_list = ids.split()
for i in id_list:
	typ, data = mail.fetch(i,'(RFC822)')
	for response_part in data:
		if isinstance(response_part, tuple):
			msg = email.message_from_string(response_part[1])
			sender = msg['from'].split()[-1]
			address = re.sub(r'[<>]','',sender)
# Ignore any occurences of own email address and add to list
	if not re.search(r'' + re.escape(LOGIN),address) and not address in email_list:
		email_list.append(address)
		print address
</pre>
<p>I&#8217;ve hard-coded my email login, password and the mailbox name, although it&#8217;s easy enough to modify the script to enter them as argmuents (I&#8217;ve commented out a line demonstrating this).</p>
<p>In a later post, I&#8217;m going to discuss how I use this script for job-seeking.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/python-script-email/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Intercepting the STDIN and STDOUT of a process with strace</title>
		<link>http://terminalinflection.com/strace-stdin-stdout/</link>
		<comments>http://terminalinflection.com/strace-stdin-stdout/#respond</comments>
		<pubDate>Wed, 29 May 2013 08:00:30 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[how to]]></category>
		<category><![CDATA[Quick & Dirty]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1615</guid>
		<description><![CDATA[There are times when debugging system behaviour when it can be very useful to see what the inputs and/or outputs of a process are: to read its STDIN and STDOUT filehandles. It can be handy to know what&#8217;s being printed to an unseen screen, particularly if there is no log file, or it may be <a href='http://terminalinflection.com/strace-stdin-stdout/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>There are times when debugging system behaviour when it can be very useful to see what the inputs and/or outputs of a process are: to read its STDIN and STDOUT filehandles.  It can be handy to know what&#8217;s being printed to an unseen screen, particularly if there is no log file, or it may be handy to snoop on what a user is typing.  This is a yet another way of using the Swiss Army knife that is <code>strace</code>.</p>
<p>In its most basic form, with few options, strace can print out every system call that a process makes, and if the &#8220;-f&#8221; or &#8220;-ff&#8221; switches are used, also print out all the system calls from the child processes that the process forks.  Like this:</p>
<pre>
  # strace -f -p &lt;PID&gt;
</pre>
<p>This provides far too much information though, so it&#8217;s often desirable to run strace with filter expressions to narrow the search down, specified with the &#8220;-e&#8221; switch.  The man page provides an exhaustive list of these filters.</p>
<p>To specify a filter for reading STDIN, STDOUT and STDERR, the following expression will do the trick:</p>
<pre>
  # strace -ff -e trace=write -e write=1,2 -p &lt;PID&gt;
</pre>
<p>Make use of this how you will.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/strace-stdin-stdout/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bash: having the last word</title>
		<link>http://terminalinflection.com/bash-last-command/</link>
		<comments>http://terminalinflection.com/bash-last-command/#respond</comments>
		<pubDate>Mon, 27 May 2013 07:58:27 +0000</pubDate>
		<dc:creator><![CDATA[Matt Parsons]]></dc:creator>
				<category><![CDATA[Quick & Dirty]]></category>
		<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://ec2-18-130-150-127.eu-west-2.compute.amazonaws.com/wordpress/?p=1620</guid>
		<description><![CDATA[Bash is the de facto shell these days, and for good reason. Most of us who peck away at our shells all day become pretty good with Bash&#8217;s keyboard shortcuts, but there&#8217;s one handy and little known shortcut that&#8217;s worth mentioning &#8211; how to recall the first word from the previous line only. You&#8217;re probably <a href='http://terminalinflection.com/bash-last-command/' class='excerpt-more'>[...]</a>]]></description>
				<content:encoded><![CDATA[<p>Bash is the de facto shell these days, and for good reason.  Most of us who peck away at our shells all day become pretty good with Bash&#8217;s keyboard shortcuts, but there&#8217;s one handy and little known shortcut that&#8217;s worth mentioning &#8211; how to recall the first word from the previous line only.</p>
<p>You&#8217;re probably used to pulling up the previous Bash line with the &#8220;Up&#8221; arrow.  You probably also frequently substitute the last word from the previous line with &#8220;Ctrl-Underscore&#8221;.  But next time you need to execute the previous command, but with a different argument, rather than hitting &#8220;Up&#8221;, deleting the last argument and retyping the new argument, try using <code>!:-</code> in place of the first word (that is, the command).</p>
<p>So if the previous command was:</p>
<pre>
   # /opt/splunk/bin/splunk start
</pre>
<p>And you next wanted to execute it again, but with a &#8220;stop&#8221; argument, do this:</p>
<pre>
   # !:- stop
</pre>
<p>The Bash shell will substitute <code>!:-</code> with the text from the previous command.  No grabbing for the mouse and copying and pasting.  Remember, according to Larry Wall, creator of Perl, <A HREF="http://threevirtues.com/">Laziness is the second virtue of the great programmer</A>.</p>
<p>
<hr>
<img style="float:left;padding:0px 10px 0px 0px" src="http://www.gravatar.com/avatar/f24d358ec0288482bc62b9cf764e8651.png">
Matt Parsons is a freelance Linux specialist who has designed, built and supported Unix and Linux systems in the finance, telecommunications and media industries. 
<br><br>
He lives and works in London.
<hr>
</p>]]></content:encoded>
			<wfw:commentRss>http://terminalinflection.com/bash-last-command/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
