<?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>Learning Perl</title>
	<atom:link href="http://www.learning-perl.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.learning-perl.com</link>
	<description></description>
	<lastBuildDate>Sun, 28 Apr 2013 23:31:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>&#8220;The stat preceding -l _ wasn&#8217;t an lstat&#8221;</title>
		<link>http://www.learning-perl.com/?p=395</link>
		<comments>http://www.learning-perl.com/?p=395#comments</comments>
		<pubDate>Sun, 28 Apr 2013 23:31:41 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[File Test Operators]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=395</guid>
		<description><![CDATA[I ran into a fatal error that I haven&#8217;t previously encountered and I couldn&#8217;t find a good explanation where I expected it. The -l file test operator can only use the virtual _ filehandle if the preceding lookup was an lstat. The file test operators, all documented under the -X entry in perlfunc, can use [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into a fatal error that I haven&#8217;t previously encountered and I couldn&#8217;t find a good explanation where I expected it. The <code>-l</code> file test operator can only use the virtual <code>_</code> filehandle if the preceding lookup was an <a href="http://perldoc.perl.org/functions/lstat.html">lstat</a>.</p>
<p>The file test operators, all documented under the <a href="http://perldoc.perl.org/functions/-X.html">-X entry in perlfunc</a>, can use the virtual filehandle <code>_</code>, the single underscore, to reuse the results of the previous file lookup. They don&#8217;t just look up the single attribute you test, but all of it (through <a href="http://perldoc.perl.org/functions/stat.html">stat</a>) which it filters to give you the answer to the question that you ask. The <code>_</code> reuses that information to answer the next question instead of looking it up again.</p>
<p>I had a program that was similar to this one, where I used some filetest operators, including the <code>-l</code> to test if it&#8217;s a symbolic link.</p>
<p><pre class="brush:perl">
use v5.14;

my $filename = join &quot;.&quot;, $0, $$, time, &#039;txt&#039;;
my $symname  = $filename =~ s/\.txt/-link.txt/r;

open my $fh, &#039;&gt;&#039;, $filename
  or die &quot;Could not open [$filename]: $!&quot;;
say $fh &#039;Just another Perl hacker,&#039;;
close $fh;

symlink $filename, $symname 
  or die &quot;Could not symlink [$symname]&quot;;

# http://perldoc.perl.org/functions/-X.html
foreach( $filename, $symname ) {
  say;
  say &quot;\texists&quot;           if -e;
  say &quot;\thas size &quot; . -s _ if -z _;
  say &quot;\tis a link&quot;        if -l _;
  }
</pre></p>
<p>I get this fatal error: </p>
<p><pre class="brush:plain">
The stat preceding -l _ wasn&#039;t an lstat at test_link_test.pl line 19
</pre></p>
<p>The entry in <a href="http://perldoc.perl.org/perlfunc.html">perlfunc</a> doesn&#8217;t say anything about this, but it hints that <code>-l</code> is a bit special:</p>
<blockquote><p>
If any of the file tests (or either the stat or lstat operator) is given the special filehandle consisting of a solitary underline, then the stat structure of the previous file test (or stat operator) is used, saving a system call. (This doesn&#8217;t work with -t , and you need to remember that lstat() and -l leave values in the stat structure for the symbolic link, not the real file.) (Also, if the stat buffer was filled by an lstat call, -T and -B will reset it with the results of stat _ ).
</p></blockquote>
<p>Adding the <a href="http://perldoc.perl.org/diagnostics.html">diagnostics</a> pragma has the answer that isn&#8217;t in <a href="http://perldoc.perl.org/perlfunc.html">perlfunc</a>:</p>
<p><pre class="brush:plain">
The stat preceding -l _ wasn&#039;t an lstat at test_link_test.pl line 19 (#1)
    (F) It makes no sense to test the current stat buffer for symbolic
    linkhood if the last stat that wrote to the stat buffer already went
    past the symlink to get to the real file.  Use an actual filename
    instead.
</pre></p>
<p>The other file test operators will perform a <a href="http://perldoc.perl.org/functions/stat.html">stat</a>. If the file is a symlink, the <a href="http://perldoc.perl.org/functions/stat.html">stat</a> follows the symlink to get the information from its target. A symlink to a symlink will even keep going until it ultimately gets to a non symlink. With a <a href="http://perldoc.perl.org/functions/stat.html">stat</a>, the <code>-l _</code> will never be true because it always ends up at the target, even if it doesn&#8217;t exist.</p>
<p>The <a href="http://perldoc.perl.org/functions/lstat.html">lstat</a> doesn&#8217;t follow the link, so it can answer the <code>-l _</code> question because it might have returned the information for a link and in the case of a non-link, it works just like <a href="http://perldoc.perl.org/functions/stat.html">stat</a>.</p>
<p>As the long version of the warning says, it&#8217;s probably better to never use the <code>_</code> filehandle and use the full filename instead. Sure, it has to redo the work, but you won&#8217;t be surprised by a fatal error if you did the wrong type of lookup before.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D395" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=395&amp;t=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=395&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D&amp;body=Link:+http://www.learning-perl.com/?p=395%0D%0A%0D%0A----%0D%0A+I+ran+into+a+fatal+error+that+I+haven%27t+previously+encountered+and+I+couldn%27t+find+a+good+explanation+where+I+expected+it.+The+-l+file+test+operato..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D&amp;summary=I+ran+into+a+fatal+error+that+I+haven%27t+previously+encountered+and+I+couldn%27t+find+a+good+explanation+where+I+expected+it.+The+-l+file+test+operato...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=395&amp;title=%E2%80%9CThe+stat+preceding+-l+_+wasn%E2%80%99t+an+lstat%E2%80%9D" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=395" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=395</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: Remove intermediate directories</title>
		<link>http://www.learning-perl.com/?p=389</link>
		<comments>http://www.learning-perl.com/?p=389#comments</comments>
		<pubDate>Thu, 18 Apr 2013 14:53:06 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=389</guid>
		<description><![CDATA[I often run into situations where I have directories that contain only one file, a subdirectory, with contain only one file, a subdirectory, and so on for a long chain, until I get to the interesting files. These situations come up when I have only part of a data set so the files that would [...]]]></description>
			<content:encoded><![CDATA[<p>I often run into situations where I have directories that contain only one file, a subdirectory, with contain only one file, a subdirectory, and so on for a long chain, until I get to the interesting files. These situations come up when I have only part of a data set so the files that would be in other directories aren&#8217;t there, and I find it annoying to deal with these long directory specifications. So, this challenge is to fix that by collapsing those one-entry directories into a single one.</p>
<p>For example, you should take this structure, where you have A/B/C/D/E in a direct line with no other branches:</p>
<div class="image center">
<div>
<img src="/images/remove_dirs/ABCDE.png" />
</div>
</div>
<p>and turn it into this one, with a single directory with the files that were at the end:</p>
<div class="image center">
<div>
<img src="/images/remove_dirs/A.png" />
</div>
</div>
<p>However, you should only moves files up if the directory above it has only one entry (which must be a subdirectory!). In this example, A/B/C has two subdirectories in it:</p>
<div class="image center">
<div>
<img src="/images/remove_dirs/ABCDFE.png" />
</div>
</div>
<p>so the the files in E should only move up into D. Otherwise, the files from the two branches in C would get mixed up with each other.</p>
<div class="image center">
<div>
<img src="/images/remove_dirs/ABCDF.png" />
</div>
</div>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+Remove+intermediate+directories+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D389" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=389&amp;t=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=389&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+Remove+intermediate+directories&amp;body=Link:+http://www.learning-perl.com/?p=389%0D%0A%0D%0A----%0D%0A+I+often+run+into+situations+where+I+have+directories+that+contain+only+one+file%2C+a+subdirectory%2C+with+contain+only+one+file%2C+a+subdirectory%2C+and+so..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories&amp;summary=I+often+run+into+situations+where+I+have+directories+that+contain+only+one+file%2C+a+subdirectory%2C+with+contain+only+one+file%2C+a+subdirectory%2C+and+so...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=389&amp;title=Learning+Perl+Challenge%3A+Remove+intermediate+directories" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=389" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=389</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why Perl&#8217;s conditional operator is right associative</title>
		<link>http://www.learning-perl.com/?p=372</link>
		<comments>http://www.learning-perl.com/?p=372#comments</comments>
		<pubDate>Wed, 27 Mar 2013 02:23:02 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[More control structures]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=372</guid>
		<description><![CDATA[What happens if you change the associativity of the conditional operator? PHP implemented it incorrectly and now it&#8217;s part of the language. In What does this PHP print?, Ovid posted a bit of PHP code that gives him unexpected results. The code comes from a much longer rant by Alex Munroe titled PHP: a fractal [...]]]></description>
			<content:encoded><![CDATA[<p>What happens if you change the associativity of the conditional operator? PHP implemented it incorrectly and now it&#8217;s part of the language. In <a href="http://blogs.perl.org/users/ovid/2013/03/what-does-this-php-print.html">What does this PHP print?</a>, Ovid posted a bit of PHP code that gives him unexpected results. The code comes from a much longer rant by Alex Munroe titled <a href="http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/">PHP: a fractal of bad design</a>:</p>
<p><br clear="all"/></p>
<p><pre class="brush:php">
&lt;?php // test.php
  $arg = &#039;T&#039;;
  $vehicle = ( ( $arg == &#039;B&#039; ) ? &#039;bus&#039; :
               ( $arg == &#039;A&#039; ) ? &#039;airplane&#039; :
               ( $arg == &#039;T&#039; ) ? &#039;train&#039; :
               ( $arg == &#039;C&#039; ) ? &#039;car&#039; :
               ( $arg == &#039;H&#039; ) ? &#039;horse&#039; :
               &#039;feet&#039; );
  echo $vehicle;
?&gt;
</pre></p>
<p>The result is <code>'horse'</code>, and it will be for almost all values of <code>$arg</code>.</p>
<p><pre class="brush:plain">
% php test.php
horse
</pre></p>
<p>I don&#8217;t care so much about the rant, but it told me the answer to this problem. The conditional operator is left associative in PHP, as documented in <a href="http://php.net/manual/en/language.operators.precedence.php">Operator Precedence</a>. That almost made sense to me, and I know that putting parentheses around these things makes it more clear. I&#8217;m almost embarrassed to say that I couldn&#8217;t do it right off in this case. Where do I put them? With other operators it&#8217;s easy because the operator characters next to each other. I started writing this to figure out the grouping when the operator characters are separated by other things.</p>
<p>Let&#8217;s simplify that a bit to we don&#8217;t have a big mess. Now there are only two:</p>
<p><pre class="brush:php">
&lt;?php // simple.php
  $arg = &#039;C&#039;;
  $vehicle = (
               ( $arg == &#039;C&#039; ) ? &#039;car&#039; :
               ( $arg == &#039;H&#039; ) ? &#039;horse&#039; : &#039;feet&#039;
             );
  echo &quot;$vehicle\n&quot;;
?&gt;
</pre></p>
<p>The result is still <code>'horse'</code> because we haven&#8217;t really changed anything:</p>
<p><pre class="brush:plain">
% php simple.php
horse
</pre></p>
<p><A href="http://blogs.perl.org/users/ovid/2013/03/what-does-this-php-print.html#comment-444852">Joel Berger</a> gave a hint when he said that changing <code>'car'</code> to <code>''</code> yields <code>'feet'</code>:</p>
<p><pre class="brush:php">
&lt;?php // null.php
  $arg = &#039;C&#039;;
  $vehicle = (
               ( $arg == &#039;C&#039; ) ? &#039;&#039; :
               ( $arg == &#039;H&#039; ) ? &#039;horse&#039; : &#039;feet&#039;
             );
  echo &quot;$vehicle\n&quot;;
?&gt;
</pre></p>
<p>And it does yield <code>'feet'</code>::</p>
<p><pre class="brush:plain">
% php null.php
feet
</pre></p>
<p>In Perl, the language I do know, the same operator is right associative (<a href="http://stackoverflow.com/q/7407273/8817">Why is the conditional operator right associative?</a> on Stackoverflow explains why). Associativity, documented in <a href="http://perldoc.perl.org/perlop.html">perlop</a>, comes into play when the compiler has to figure out which operator to do first when it has the same operator next to each other. In <i>Learning Perl</i>, we show this with the expontentiation operator since many other operators, such as multiplication and addition, don&#8217;t really care. The expontentiation is right associative because that&#8217;s what Larry decided it was (C doesn&#8217;t have this operator). That means it does the operation on the right before it does the operation on the left. You can see this when you use parentheses, the highest precedence operator, to denote the order you want and compare it to the version without the explicit grouping:</p>
<p><pre class="brush:perl">
my $num = 4**3**2;    # 262144
my $num = 4**(3**2);  # 262144
my $num = (4**3)**2;  # 4096
</pre></p>
<p>We can do the same for the conditional operator in Perl. First, we translate the code to PHP, which is mostly changing <code>==</code> to <code>eq</code>:</p>
<p><pre class="brush:perl">
# perl.pl
use v5.10;

my $arg = &#039;C&#039;;
my $vehicle = (
               ( $arg eq &#039;C&#039; ) ? &#039;car&#039; :
               ( $arg eq &#039;H&#039; ) ? &#039;horse&#039; : &#039;feet&#039;
             );
say $vehicle;

&lt;pre class=&quot;brush:plain&quot;&gt;
% perl.pl
car
</pre></p>
<p>In Perl, we get the same behavior if we put parentheses around the second conditional:</p>
<p><pre class="brush:perl">
# right.pl
use v5.10;

my $arg = &#039;C&#039;;
my $vehicle = (
               ( $arg eq &#039;C&#039; ) ? &#039;car&#039; :
               ( ( $arg eq &#039;H&#039; ) ? &#039;horse&#039; : &#039;feet&#039; )
             );
say $vehicle;
</pre></p>
<p>We get the same result as <i>perl.pl</i> because we haven&#8217;t changed the order of anything:</p>
<p><pre class="brush:plain">
% perl right.pl
car
</pre></p>
<p>To get the PHP behaviour, we have to change the parentheses like this, to surround everything up to the next <code>?</code>. It took quite a mental leap for me to get this far because it&#8217;s so unnatural:</p>
<p><pre class="brush:perl">
# left.pl
use v5.10;

my $arg = &#039;C&#039;;                                                        
my $vehicle = (
               ( ( $arg eq &#039;C&#039; ) ? &#039;car&#039; : ( $arg eq &#039;H&#039; ) ) 
                 ? &#039;horse&#039; : &#039;feet&#039;
             );
say $vehicle;
</pre></p>
<p>Now we get different behaviour:</p>
<p><pre class="brush:plain">
% perl left.pl
horse
</pre></p>
<p>That&#8217;s really odd, but it&#8217;s also a small gotcha we mention in the <i>Learning Perl</i> class. You can have things such as <code> ( $arg == 'H' )</code> as a branch. This use probably isn&#8217;t useful, but it&#8217;s a consequence of the syntax. We can do assignments, for instance:</p>
<p><pre class="brush:perl">
my $result = $value ? ( $n = 5 ) : ( $m = 6 );
</pre></p>
<p>It&#8217;s easier to see this as a picture for the path through the conditionals. The right associative version branches either to an endpoint or another decision and there&#8217;s only one way to get to that endpoint.</p>
<div class="image center">
<div>
<img src="/images/php-conditional/right.png" /></p>
<p>Right associative, as in Perl</p>
</div>
</div>
<p>The left associative version has multiple ways to get to the same endpoint because either branch in the previous conditional can be the value for the next test. This also shows how <code>'car'</code> isn&#8217;t the endpoint that you think it should be:</p>
<div class="image center">
<div>
<img src="/images/php-conditional/left.png" /></p>
<p>Left associative, as in PHP</p>
</div>
</div>
<p>Going back to do the same thing with the original chain of conditionals, we get this diagram that looks more like a <A href="http://www.eveningarwen.com/modules/general/faqs/1/How-do-I-lace-my-corset/">corset lacing instruction</a> than something we meant to program.</p>
<div class="image center">
<div>
<img src="/images/php-conditional/full.png" /></p>
<p>The full monty</p>
</div>
</div>
<p>However, we already know the answers in this particular case because some values are literals, so we can remove several paths. Now it&#8217;s much more clear that many paths are feeding into a path that must end up at <code>'horse'</code>. </p>
<div class="image center">
<div>
<img src="/images/php-conditional/trimmed.png" /></p>
<p>The full monty</p>
</div>
</div>
<p>In fact, the only way to get to <code>'feet'</code> is to be any letter that is not <i>B</i>, <i>A</i>, <i>T</i>, <i>C</i>, or <i>H</i>. Joel figured this out by changing <code>'car'</code> to the empty string, which has this diagram:</p>
<div class="image center">
<div>
<img src="/images/php-conditional/joel.png" /></p>
<p>Joel&#8217;s change</p>
</div>
</div>
<p>The only way to get to <code>'horse'</code> is to be exactly <i>H</i>. The other letters must end up at <code>'feet'</code> because they all end up at the empty string. Every other string ends up at <code>'feet'</code> because they are not exactly <i>H</i>.</p>
<p>Maybe the complicated stuff makes sense to PHP programmers. I don&#8217;t know. It&#8217;s more likely that they don&#8217;t do these sorts of things, at least if they&#8217;ve read the <A href="http://php.net/ternary#example-120">advice in the PHP manual</a>. Some people blame Perl since PHP inherited from Perl, but it seems like a yacc error that they can&#8217;t fix for backward compatibility. It&#8217;s not like that&#8217;s never happened to Perl </p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Why+Perl%E2%80%99s+conditional+operator+is+right+associative+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D372" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=372&amp;t=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=372&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Why+Perl%E2%80%99s+conditional+operator+is+right+associative&amp;body=Link:+http://www.learning-perl.com/?p=372%0D%0A%0D%0A----%0D%0A+What+happens+if+you+change+the+associativity+of+the+conditional+operator%3F+PHP+implemented+it+incorrectly+and+now+it%27s+part+of+the+language.+In+What..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative&amp;summary=What+happens+if+you+change+the+associativity+of+the+conditional+operator%3F+PHP+implemented+it+incorrectly+and+now+it%27s+part+of+the+language.+In+What...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=372&amp;title=Why+Perl%E2%80%99s+conditional+operator+is+right+associative" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=372" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=372</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: popular history (Answer)</title>
		<link>http://www.learning-perl.com/?p=356</link>
		<comments>http://www.learning-perl.com/?p=356#comments</comments>
		<pubDate>Sun, 24 Feb 2013 13:37:23 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=356</guid>
		<description><![CDATA[June&#8217;s challenge counted the most popular commands from a shell history. Some shells remember the last commands you used so you can start a new session and still have them available. For this exercise, I&#8217;ll assume the bash shell. You setup the history feature by telling your shell to track the history. You want to [...]]]></description>
			<content:encoded><![CDATA[<p><A href="http://www.learning-perl.com/?p=302">June&#8217;s challenge</a> counted the most popular commands from a shell history. Some shells remember the last commands you used so you can start a new session and still have them available. For this exercise, I&#8217;ll assume the <i>bash</i> shell.</p>
<p>You setup the history feature by telling your shell to track the history. You want to remember 3,000 previous commands:</p>
<p><pre class="brush:plain">
HISTFILE=/Users/brian/.bash_history
HISTFILESIZE=3000
HISTSIZE=1500
</pre></p>
<p>There&#8217;s much you can do with your command history, but that&#8217;s not what I&#8217;m covering here. The <a href="http://www.catonmat.net/blog/the-definitive-guide-to-bash-command-line-history/">bash history cheat sheet</a> explains most of it.</p>
<p>There are two ways you can get at the history. You can run the <code>history</code> command and pipe it to your Perl program as standard input, or you can read the history file (perhaps also piping it at standard input). The shell only writes to the file at the end of the session, so the file doesn&#8217;t know about recent commands. Also, each session merely appends to the file. Each session&#8217;s history is contiguous, so the file is not necessarily chronological. This doesn&#8217;t matter much to the challenge to find the overall popular commands.</p>
<p>Once you get the input, you have to figure out which part is the command. There are several issues there too. The first part of the line might be the command, a path to the command, or some sort of modifier for the command. A command line might have a pipeline of multiple commands or a series of separate commands. Some of the commands might be shell built-ins while others are external programs. Some commands might be user-defined aliases:</p>
<p><pre class="brush:plain">
tail -f /var/log/system.log
/usr/bin/tail/ -f /var/log/system.log
sudo vi /etc/groups
history | perl -pe &#039;s/\A\s*\d+\s*//&#039;
grep ^_x /etc/passwd | cut -d : -f 1,5 | perl -C -Mutf8 -pe &#039;s/:/ → /g&#039;
(cd /git/dumbbench; git pull origin master)
perldoc -l SQL::Parser | xargs bbedit
export HISTFILESIZE=3000
l
</pre></p>
<p>This breaks the challenge into three parts, the last of which is basic accumulator stuff that we show <i>Learning Perl</i> for many tasks.</p>
<ol>
<li>Get the history
<li>Extract the commands
<li>Count and report the results
</ol>
<p>I&#8217;ll cover each of those parts separately as I go through the answers.</p>
<h3>Get the history</h3>
<p>Most people opened a filehandle on the history file. Some people hard-coded the path while others made it relative to the home directory:</p>
<p><pre class="brush:perl">
open( FILE, &quot;/Users/me/.bash_history&quot; );     # rm

my $hist_file = &quot;$ENV{HOME}/.bash_history&quot;;  # jose
open my $hf, &quot;&lt;&quot;, $hist_file;

my $path    = $ENV{HOME};                    # Dave M
my $history = $path . &#039;/&#039; . &#039;.bash_history&#039;;
open( my $f, &#039;&lt;&#039;, $history );

open HISTORY, $ENV{&#039;HOME&#039;}.&#039;/.bash_history&#039;  # ulric
  or die &quot;Cannot open .bash_history: $!&quot;;
</pre></p>
<p>Daniel Keane was the only person to use <i>zsh</i>, which has a history format with timestamps (one of the issues I noted with the <i>bash</i> history):</p>
<p><pre class="brush:perl">
my $history_path = &quot;$ENV{&#039;HOME&#039;}/.zhistory&quot;;
die &quot;Cannot locate file: $history_path&quot; unless -e $history_path;
open(my $history_fh, &#039;&lt;&#039;, $history_path);
</pre></p>
<p>Neil Bowers used <A href="https://www.metacpan.org/module/File::Slurp">File::Slurp</a> to get it all at once:</p>
<p><pre class="brush:perl">
read_file($ENV{&#039;HOME&#039;}.&#039;/.bash_history&#039;, chomp =&gt; 1);
</pre></p>
<p>Anonymous Coward set a default value for the history file but also allows people to override it with a command-line option:</p>
<p><pre class="brush:perl">
my $histfile = &quot;$ENV{HOME}/.bash_history&quot;;
my $position = 0;
my $number = 10;
GetOptions (
  &#039;histfile=s&#039; =&gt; \$histfile,
  &#039;position=i&#039; =&gt; \$position,
  &#039;number=i&#039;   =&gt; \$number,
);
</pre></p>
<p>A couple of people shelled out to run the <code>history</code> command. WK used <code>history -r</code> to add the history from the history file to the current history, then read the history from the command line:</p>
<p><pre class="brush:perl">
  my @history = qx/$ENV{ SHELL } -i -c &quot;history -r; history&quot;/; # WX
</pre></p>
<p>Javier&#8217;s answer did much of the work in the shell and <code>awk</code>:</p>
<p><pre class="brush:perl">
    my $get_cmds =
        qq/$ENV{&#039;SHELL&#039;} -i -c &quot;history -r; history&quot;/
        . q/ | awk &#039;{for (i=2; i&amp;gt;NF; i++) printf $i &quot; &quot;; print $NF}&#039;/;

    chomp(my @cmds = qx# $get_cmds #);
</pre></p>
<p>The two winners for getting the data, however, are the two people who provided one-liners. They used standard input, which means they could handle either a file in <code>@ARGV</code> or a pipe from <code>history</code>:</p>
<p>VINIAN might get a <A href="http://partmaps.org/era/unix/award.html">&#8220;Useless use of cat Award&#8221;</a>, something Perl&#8217;s Randal Schwartz used to hand out. The <code>-a</code> switch (see <a href="http://perldoc.perl.org/perlrun.html">perlrun</a> splits on whitespace and puts the list in <code>@F</code>:</p>
<p><pre>
% cat ~/.bash_history | perl  -lane &#039;if ($F[0] eq &quot;sudo&quot;){$hash{$F[1]}++ } else { $hash{$F[0]}++ }; $count ++; END { @top = map {  [ $_, $hash{$_} ] } sort { $hash{$b}  &lt;=&gt; $hash{$a} } keys %hash; @max=@top[0..9]; printf(&quot;%10s%10d%10.2f%%\n&quot;, $_-&gt;[0], $_-&gt;[1], $_-&gt;[1]/$count*100) for @max}&#039;
</pre></p>
<p>But, VINIAN&#8217;s program would work with a file argument, As Chris Fedde uses:</p>
<p><pre class="brush:perl">
% perl -lanE &#039;$sum{$F[0]}++; END{ say &quot;$_ $sum{$_}&quot; for (reverse sort {$sum{$a}  &lt;=&gt; $sum{$b}} keys %sum)}&#039; ~/.bash_history | less
</pre></p>
<p>I would think that a better answer to this part would examine the environment variable for <code>HISTFILE</code>, but jose notes that it doesn&#8217;t work on cygwin. I did not investigate that.</p>
<h3>Extract the commands</h3>
<p>Extracting the commands is the tough part of the problem, but many people skipped most of that problem. They assumed the first group of non-whitespace was the command, possibly turning an absolute path to its basename.</p>
<p>jose used <code>basename</code> is the command started with a <code>/</code>:</p>
<p><pre class="brush:perl">
$cmd = basename $cmd if $cmd and $cmd =~ /\//;
</pre></p>
<p>You don&#8217;t really need to check that though. You could just take the basename though, as Dave M did unconditionally:</p>
<p><pre class="brush:perl">
my $basename = basename( $args[0] );
</pre></p>
<p>This ignores something that would be harder to solve; what if two different commands have the same name? For instance, the system <code>perl</code> and a user-installed one might have the same name. Either might be specified as just <code>perl</code> depending on the <code>PATH</code>, and the user-installed one might be a relative path. Most people counted the basename only.</p>
<p>Some people took the commands and checked that they were in the <code>PATH</code>:</p>
<p><pre class="brush:perl">
    for my $p (@paths) {
        if ( -e &quot;$p/$basename&quot; ) {
            $words{$basename}++;
        }
    }
</pre></p>
<p>No one checked for symbolic links.</p>
<p>WK is the only person who translated aliases:</p>
<p><pre class="brush:perl">
my %alias = get_aliases_hash();

sub get_aliases_hash {
  my @alias = qx/$ENV{&#039;SHELL&#039;} -i -c &quot;alias&quot;/;
  return map { m/\Aalias\s+(.+)=&#039;(.+)&#039;\s*$/; $1 =&gt; $2 } @alias;
}
</pre></p>
<p>ulric and WK are the only people who didn&#8217;t count <code>sudo</code> by skipping it. Here&#8217;s how ulric did it:</p>
<p><pre class="brush:perl">
  if ($commandline[0] =~ &#039;sudo&#039;) {
    shift @commandline;
  } # sudo is ignored as a metacommand
</pre></p>
<p>I think most people get fair marks for this part, but if I had to choose a winner, I&#8217;d go with WK.</p>
<h3>Count and report the results</h3>
<p>Once you have the commands, most people used the command as a hash key and adding one to the value. There&#8217;s not too much interesting there.</p>
<h3>My Answer</h3>
<p>My answer differs substantially only in the way that I examine the command line. I know about the <a href="https://www.metacpan.org/module/Text::ParseWords">Text::ParseWords</a> module that can break up a line like the shell would. This is, it can break up a line while preserving quoting. I want to handle the shell special separators <code>;</code> and <code>|</code> except when they are parts of quoted strings. The <code>parse_lines</code> can handle that:</p>
<p><pre class="brush:perl">;
my $delims = &#039;(?:\s+|\||;)&#039;;
parse_line( $delims, &#039;delimiters&#039;, $_ );
</pre></p>
<p>The first argument is the regular expression I use to recognize a delimiter outside of a quoted string. I can&#8217;t rely on whitespace (although at first I tried), but the shell can handle things such as <code>tail -f file|perl -pe '...'</code> where the separator has no whitespace around it.</p>
<p>The second argument, if it is the special value <code>delimiters</code>, returns the delimiter string. I need to use this to recognize the start of new commands on the same line.</p>
<p>My program is long and not very fun, since I limit myself to the material in <i>Learning Perl</i>. Fun things such as <a href="http://perldoc.perl.org/functions/splice.html">splice</a> only show up as &#8220;things we didn&#8217;t cover&#8221;. It&#8217;s in the <A href="https://github.com/briandfoy/learning-perl-challenges">Learning Perl Challenges</a> GitHub repository with my other answers.</p>
<p>As well as keeping track of the commands, I track which ones were modified by other commands that I specify in <code>%modifiers</code>. I didn&#8217;t handle aliases or basenames like many other people did:</p>
<p><pre class="brush:perl">
#!perl
use v5.10;
use strict;
use warnings;

use Text::ParseWords;

my %commands;
my %modifieds;

my $N = 10;

my %modifiers = map { $_, 1 } qw( sudo xargs );
my $delims = &#039;(?:\s+|\||;)&#039;;

while( &lt;&gt; ) {
  my @shellwords    = 
    grep { defined &amp;&amp; /\S/ }
    parse_line( $delims, &#039;delimiters&#039;, $_ );
  next unless @shellwords;

  my @start_indices = get_starts( @shellwords );

  # go through the shellwords to find the delimiters like ; and |
  # one command line can have multiple commands, so find all of 
  # them.
  I: foreach my $i ( 0 .. $#start_indices ) {
    my( $start, $end ) = ( 
      $start_indices[$i], 
      $i &lt; $#start_indices ? $start_indices[$i+1] - 1 : $#shellwords
      );
    
    # look through a command group to find the the command
    my $modified = 0;
    J: foreach my $j ( $start .. $end ) {
      next if $shellwords[$j] =~ m/\A$delims\Z/;
      if( exists $modifiers{$shellwords[$j]} ) {
        $modified = $shellwords[$j];
        next;
        }
      if( $modified ) {
        $modifieds{&quot;$modified $shellwords[$j]&quot;}++;
        }
      $commands{$shellwords[$j]}++;
      last J;
      }
    }  
  }

say &quot;------ Top commands&quot;;
report_top_ten( $N, %commands );

say &quot;------ Top modified commands&quot;;
report_top_ten( $N, %modifieds );

sub get_starts {
  my @starts = 0;
  while ( my( $i, $value ) = each @_ ) {
    push @starts, $i if $value =~ /\A$delims\z/;
    }
  return @starts;
  }

sub report_top_ten {
  my( $top_count, %hash ) = @_;
  
  my @top_commands  = sort { $hash{$b} &lt;=&gt; $hash{$a} } keys %hash;
  my $max_width = length $hash{$top_commands[0]};
  while( my( $i, $value ) = each @top_commands ) {
    last if $i &gt;= $top_count;
    printf &#039;%*d %s&#039; . &quot;\n&quot;, $max_width, $hash{$top_commands[$i]}, $top_commands[$i];
    }
  }
</pre></p>
<p>And, with that, I find my top commands by reading from standard input and using my environment variable to locat the file:</p>
<p><pre class="brush:plain">
$ perl history.pl $HISTFILE
------ Top commands
843 make
518 perl
364 ls
343 git
244 cd
156 bb
117 open
 68 pwd
 51 rm
 42 ssh
------ Top modified commands
3 xargs rm
2 xargs bbedit
2 xargs bb
1 xargs stripper
1 sudo cp
</pre></p>
<p>The <code>bb</code> is an alias for <code>bbedit</code>, the command-line program to do various things with that GUI editor. The <code>stripper</code> is a program I use to remove end-of-line whitespace. I most often use it with <code>find</code>, which is why it shows up after <code>xargs</code>.</p>
<p>That <code>make</code> comes mostly as <code>make test</code>, and the <code>perl</code> as <code>perl Makefile.PL</code>.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+popular+history+%28Answer%29+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D356" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=356&amp;t=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=356&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+popular+history+%28Answer%29&amp;body=Link:+http://www.learning-perl.com/?p=356%0D%0A%0D%0A----%0D%0A+%0D%0AJune%27s+challenge+counted+the+most+popular+commands+from+a+shell+history.+Some+shells+remember+the+last+commands+you+used+so+you+can+start+a+new+s..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29&amp;summary=%0D%0AJune%27s+challenge+counted+the+most+popular+commands+from+a+shell+history.+Some+shells+remember+the+last+commands+you+used+so+you+can+start+a+new+s...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=356&amp;title=Learning+Perl+Challenge%3A+popular+history+%28Answer%29" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=356" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=356</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: directory with the most files</title>
		<link>http://www.learning-perl.com/?p=342</link>
		<comments>http://www.learning-perl.com/?p=342#comments</comments>
		<pubDate>Sat, 09 Feb 2013 05:07:41 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=342</guid>
		<description><![CDATA[Find the top 10 directories on your system that has the most files in it. For that, only count the files immediately under it. That is, don&#8217;t count files in subdirectories. For file, I mean just about anything that isn&#8217;t a symbolic link or weird device. Think about how you want to show the person [...]]]></description>
			<content:encoded><![CDATA[<p>Find the top 10 directories on your system that has the most files in it. For that, only count the files immediately under it. That is, don&#8217;t count files in subdirectories. For file, I mean just about anything that isn&#8217;t a symbolic link or weird device. Think about how you want to show the person running your program what it&#8217;s doing.</p>
<p>This challenge isn&#8217;t about counting so much as traversing, remembering, and displaying. How do you know what you need to handle next and which one was largest?</p>
<p>I&#8217;m actually writing my own version of this right now because I&#8217;m making some benchmarks on <code>opendir</code> versus <code>glob</code> and need some test cases. I could just create some new directories and make a bunch of fake files in them, but that&#8217;s no fun.</p>
<p>I don&#8217;t care how long your program takes, although you might. Let it run in a window (or screen) on its own. Test it on a small directory first (so, there&#8217;s a hint there).</p>
<p>I made a Curses version (but don&#8217;t look at it until you&#8217;ve tried your own solution!):</p>
<div align="center">
<iframe width="560" height="315" src="http://www.youtube.com/embed/UOqhg1n9KKo" frameborder="0" allowfullscreen></iframe>
</div>
<p>You can see <A href="http://www.learning-perl.com/?page_id=289">a list of all Challenges and my summaries</a> as well as the programs that I created and put in the <a href="https://github.com/briandfoy/learning-perl-challenges<br />
">Learning Perl Challenges</a> GitHub repository.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+directory+with+the+most+files+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D342" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=342&amp;t=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=342&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+directory+with+the+most+files&amp;body=Link:+http://www.learning-perl.com/?p=342%0D%0A%0D%0A----%0D%0A+Find+the+top+10+directories+on+your+system+that+has+the+most+files+in+it.+For+that%2C+only+count+the+files+immediately+under+it.+That+is%2C+don%27t+count..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files&amp;summary=Find+the+top+10+directories+on+your+system+that+has+the+most+files+in+it.+For+that%2C+only+count+the+files+immediately+under+it.+That+is%2C+don%27t+count...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=342&amp;title=Learning+Perl+Challenge%3A+directory+with+the+most+files" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=342" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=342</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>50% off Learning Perl Video Series during OSCON</title>
		<link>http://www.learning-perl.com/?p=331</link>
		<comments>http://www.learning-perl.com/?p=331#comments</comments>
		<pubDate>Mon, 16 Jul 2012 20:50:28 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=331</guid>
		<description><![CDATA[During OSCON, you can get Randal&#8217;s Schwartz&#8217;s Learning Perl Video Series for $74.99 (50% off). This is the same class that Stonehenge presents to its corporate clients, based on Learning Perl (or, more correctly, the book is based on the class). You can also get the Programming Perl ebook for $19.99 (50% the list price) [...]]]></description>
			<content:encoded><![CDATA[<div class="image right">
<div>
<a href="http://shop.oreilly.com/product/0636920014430.do?code=CFOSCON"><img src="http://akamaicovers.oreilly.com/images/0636920014430/cat.gif"/></a>
</div>
</div>
<p>During <a href="http://www.oscon.com">OSCON</a>, you can get <a href="http://shop.oreilly.com/product/0636920014430.do?code=CFOSCON">Randal&#8217;s Schwartz&#8217;s <i>Learning Perl Video Series</i></a> for $74.99 (50% off). This is the same class that Stonehenge presents to its corporate clients, based on <i>Learning Perl</i> (or, more correctly, the book is based on the class).</p>
<p>You can also get the <a href="http://shop.oreilly.com/product/9780596004927.do?code=CFOSCON"><i>Programming Perl</i></a> ebook for $19.99 (50% the list price) when you buy it through <a href="http://shop.oreilly.com/category/deals/oscon.do?cmp=tw-code-lp-opensource-geeks">the open source geeks promotion</a> or by using offer code CFOSCON. </p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=50%25+off+Learning+Perl+Video+Series+during+OSCON+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D331" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=331&amp;t=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=331&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=50%25+off+Learning+Perl+Video+Series+during+OSCON&amp;body=Link:+http://www.learning-perl.com/?p=331%0D%0A%0D%0A----%0D%0A+%0D%0A%0D%0A%0D%0A%0D%0A%0D%0A%0D%0ADuring+OSCON%2C+you+can+get+Randal%27s+Schwartz%27s+Learning+Perl+Video+Series+for+%2474.99+%2850%25+off%29.+This+is+the+same+class+that+Stonehenge+p..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON&amp;summary=%0D%0A%0D%0A%0D%0A%0D%0A%0D%0A%0D%0ADuring+OSCON%2C+you+can+get+Randal%27s+Schwartz%27s+Learning+Perl+Video+Series+for+%2474.99+%2850%25+off%29.+This+is+the+same+class+that+Stonehenge+p...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=331&amp;title=50%25+off+Learning+Perl+Video+Series+during+OSCON" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=331" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=331</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: popular history</title>
		<link>http://www.learning-perl.com/?p=302</link>
		<comments>http://www.learning-perl.com/?p=302#comments</comments>
		<pubDate>Wed, 27 Jun 2012 02:27:45 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=302</guid>
		<description><![CDATA[For June&#8217;s challenge, write a program to read the history of shell commands and determine which ones you use the most. In bash, you can set the HISTFILE and HISTFILESIZE to control history&#8216;s behavior. To get the commands to count, you can read the right file or shell out to the history command. From there, [...]]]></description>
			<content:encoded><![CDATA[<p>For June&#8217;s challenge, write a program to read the history of shell commands and determine which ones you use the most.</p>
<p>In <i>bash</i>, you can set the <code>HISTFILE</code> and <code>HISTFILESIZE</code> to control <code>history</code>&#8216;s behavior. To get the commands to count, you can read the right file or shell out to the <code>history</code> command. From there, you have to decide how to split up each line to figure out what the command is. Can you handle commands with relative paths and absolute paths so you don&#8217;t count them separately?</p>
<p>This was an meme for a little while, and I wish I could find my answer to it. If you find my answer, please let me know.</p>
<p>You can see <A href="http://www.learning-perl.com/?page_id=289">a list of all Challenges and my summaries</a> as well as the programs that I created and put in the <a href="https://github.com/briandfoy/learning-perl-challenges<br />
">Learning Perl Challenges</a> GitHub repository.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+popular+history+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D302" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=302&amp;t=Learning+Perl+Challenge%3A+popular+history" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=302&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+popular+history&amp;body=Link:+http://www.learning-perl.com/?p=302%0D%0A%0D%0A----%0D%0A+For+June%27s+challenge%2C+write+a+program+to+read+the+history+of+shell+commands+and+determine+which+ones+you+use+the+most.%0D%0A%0D%0AIn+bash%2C+you+can+set+the+..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history&amp;summary=For+June%27s+challenge%2C+write+a+program+to+read+the+history+of+shell+commands+and+determine+which+ones+you+use+the+most.%0D%0A%0D%0AIn+bash%2C+you+can+set+the+...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=302&amp;title=Learning+Perl+Challenge%3A+popular+history" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=302" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=302</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Learning Perl Giveaway</title>
		<link>http://www.learning-perl.com/?p=327</link>
		<comments>http://www.learning-perl.com/?p=327#comments</comments>
		<pubDate>Tue, 26 Jun 2012 06:38:43 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[giveaways]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=327</guid>
		<description><![CDATA[I&#8217;ve found another extra copy of Learning Perl, 6th Edition, and I&#8217;m going to give it away. In previous giveaways I&#8217;ve been creative, sometimes asking people to send me a postcard, donate to a charity, or something else. I&#8217;m not going to give people a book without getting something from them. This time, I&#8217;ll send [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve found another extra copy of <i>Learning Perl, 6th Edition</i>, and I&#8217;m going to give it away. In previous giveaways I&#8217;ve been creative, sometimes asking people to send me a postcard, donate to a charity, or something else. I&#8217;m not going to give people a book without getting something from them.</p>
<p>This time, I&#8217;ll send this book to someone who wants to replace their current <i>Learning Perl</i> or other beginning Perl book. Post a picture of yourself with the book you&#8217;d like to replace and link to this blog post, along with a short explanation why you need to replace your Perl book. The picture has to be available to anyone without logging in to any sort of account, and licensed under a share-alike agreement so I can repost my favorite photos. Don&#8217;t hide your picture in Facebook!</p>
<div class="image center">
<div>
<img src="http://a.yfrog.com/img734/1926/p5lk.jpg" width="500"/></p>
<p>A photo that Schwern might submit if he wanted a free book</p>
</div>
</div>
<p>By the end of July, I&#8217;ll choose the picture that I like the most and send that person a free <i>Learning Perl</i> signed by me.</p>
<p>I might favor some items in your photo, and give even more favor to photos that combine those elements.</p>
<ul>
<li>Famous landmarks
<li>Bigfoot
<li>Scenery used in a movie (leaning toward New Zealand here)
<li>Very large beers
<li>Military matériel
<li>Llamas
</ul>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Giveaway+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D327" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=327&amp;t=Learning+Perl+Giveaway" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=327&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Giveaway&amp;body=Link:+http://www.learning-perl.com/?p=327%0D%0A%0D%0A----%0D%0A+I%27ve+found+another+extra+copy+of+Learning+Perl%2C+6th+Edition%2C+and+I%27m+going+to+give+it+away.+In+previous+giveaways+I%27ve+been+creative%2C+sometimes+ask..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway&amp;summary=I%27ve+found+another+extra+copy+of+Learning+Perl%2C+6th+Edition%2C+and+I%27m+going+to+give+it+away.+In+previous+giveaways+I%27ve+been+creative%2C+sometimes+ask...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=327&amp;title=Learning+Perl+Giveaway" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=327" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=327</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: finding duplicates (Answer)</title>
		<link>http://www.learning-perl.com/?p=317</link>
		<comments>http://www.learning-perl.com/?p=317#comments</comments>
		<pubDate>Wed, 20 Jun 2012 02:25:05 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=317</guid>
		<description><![CDATA[March&#8217;s challenge was to find duplicate files. I often write a quick and dirty program to do this, having forgotten what I called the program or having failed to copy it to all of my accounts. This program helps me find extra copies of files that are taking up my space on Dropbox. Did I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.learning-perl.com/?p=286">March&#8217;s challenge was to find duplicate files</a>. I often write a quick and dirty program to do this, having forgotten what I called the program or having failed to copy it to all of my accounts. This program helps me find extra copies of files that are taking up my space on Dropbox. Did I really mean to have two copies of the OS X Lion installer? I had already downloaded it, moved it into the wrong folder, and forgotten about it. I downloaded it again, moved it into the right folder, and took up another 2% of my Dropbox space. Or, iTunes stupidly stores the same file twice, in the same folder even, with slightly different names (and that&#8217;s in Dropbox too).</p>
<p>Before I go through the posted solutions for the challenge, I&#8217;ll show you mine. It&#8217;s not at all impressive and not that efficient. It&#8217;s not even pretty, but this is the program I hacked up a long time ago to do this. I spend five minutes thinking about it, let it run, and moved on:</p>
<p><pre class="brush:perl">
use File::Find;
use Digest::MD5;

find( \&amp;wanted, grep { -e } @ARGV );

our %digests;
sub wanted {
  return if( -d $File::Find::name or -l $File::Find::name );
  my $fh;
  unless( open $fh, &#039;&lt;&#039;, $File::Find::name ) {
    warn &quot;$File::Find::name: $!&quot;;
    return;
    }

  my $digest = Digest::MD5-&gt;new-&gt;addfile($fh)-&gt;hexdigest;
  
  $digests{$digest} .= &quot;$File::Find::name\000&quot;;
  }

foreach my $digest ( keys %digests ) {
  my @files = split /\000/, $digests{$digest};
  next unless @files &gt; 1;
  print join( &quot;\n\t&quot;, @files ), &quot;\n\n&quot;;
  }
</pre></p>
<p>As some people noted in their solutions, various digests have problems. We want a digest that is a short representation of content and is unlikely to be the same for different content. The chances of a &#8220;collision&#8221; depend on the algorithm as well as the number of times we try it. If we only digest one file, we never have a collision. If digest ten files, we expect a collision to be extremely rare. When (not if) we get to billions of files, weak algorithms will fail us. Since I don&#8217;t care that much, I use MD5. But, I&#8217;ve segregated all of those details in a subroutine, so I can easily change that.</p>
<p>Aside from that, this is essentially an exercise in file system traversal and hashes. However I decide to compare files, I need to store earlier results. I limit myself to the concepts in <i>Learning Perl</i>, so I don&#8217;t use an array reference as the value in <code>%digests</code>. Instead, I store all filenames in a single string by separating them with a null byte (<code>\000</code>). Later,<br />
I <a href="http://perldoc.perl.org/functions/split.html">split</a> them again to get the list of files.</p>
<p>Since I&#8217;m writing a simple program, I merely report the duplicates as I find them. I want to inspect the files myself before I delete or move them.</p>
<p>My solution has problems. I have to wait for <code>find</code> to do its work before I start seeing a report of the duplicates. That&#8217;s rather annoying. However, when I use this, I usually don&#8217;t care how fast I get the results. It is a bit of ugly programming, but it works.</p>
<h2>The solutions</h2>
<p>Although people have their particular coding styles, there are three ways these programs can be conceptually different:</p>
<ol>
<li>Finding the files
<li>Digesting the files
<li>Reporting the duplicates
</ol>
<h3>Finding files</h3>
<p>There are a few ways to find the files. The easiest is <a href="https://www.metacpan.org/module/File::Find">File::Find</a>, which does a depth-first search by using a callback. It&#8217;s the easiest thing to start with, and many people did. It&#8217;s what I used. </p>
<p><a href="http://www.learning-perl.com/?p=286#comment-1014">Tudor makes his own recursive subroutine</a> to get all the files out of a directory and its subdirectories, effectively reinventing <a href="https://www.metacpan.org/module/File::Find">File::Find</a>:</p>
<p><pre class="brush:perl; first-line:14">
sub _process_folder{
    my $folder_name = shift;

    foreach my $file_name ( glob  &quot;$folder_name/*&quot; ){
        #nothing to do if current, or parent directory
        next if $file_name ~~ [ qw/. ../ ];

        # $file_name might actually be a folder
        if ( -d $file_name ){
            _process_folder($file_name);
            next ;
        };

        my $file_content = read_file( $file_name, binmode =&gt; &#039;:raw&#039; );
        if ( defined($duplicate_files-&gt;{ md5_hex( $file_content ) }) ){
            push @{ $duplicate_files-&gt;{ md5_hex( $file_content ) } }, $file_name;
        } else {
            $duplicate_files-&gt;{ md5_hex( $file_content ) } = [ $file_name ];
        };
    }

    return;
}
</pre></p>
<p><a href="http://www.learning-perl.com/?p=286#comment-1227">Mr. Nicholas uses a glob</a> to get all the files in the current working directory:</p>
<p><pre class="brush:perl; first-line:8">
while (&lt;*&gt;) {
    push @{$data{md5_hex(read_file($_))}},$_ if -f $_;
}
</pre></p>
<p>I&#8217;d rather use <a href="http://perldoc.perl.org/functions/glob.html">glob</a> if I wanted a list of files so I can save the angle brackets for reading lines. That&#8217;s what <a href="http://www.learning-perl.com/?p=286#comment-1097">ulric did</A>:</p>
<p><pre class="brush:perl; first-line:10">
my @files=glob&#039;*&#039;;
</pre></p>
<p><a href="http://www.learning-perl.com/?p=286#comment-1401">Eric used readdir</a>, and gets all the files at once:</p>
<p><pre class="brush:perl; first-line:10">
opendir DIR, $ARGV[0]
    or die &quot;opendir error: $!&quot;;
my @files = readdir DIR;
my %fp;
</pre></p>
<p>The other solutions that don&#8217;t use <a href="https://www.metacpan.org/module/File::Find">File::Find</a> only work with the current directory, which is what I specified for the basic parts of this problem. I&#8217;ll have to give no points to those solutions for this part—neither extra points or demerits. They pass, while other solutions did the extra parts to handle subdirectories.</p>
<h3>Digesting files</h3>
<p><a href="http://www.learning-perl.com/?p=286#comment-979">On his first go, Anonymous Coward</a> went for <a href="https://www.metacpan.org/module/Digest">Digest</a>, which handles many types of digests with the same interface. He went with SHA-256. On his first try, he hardcoded the digest and used a variable name tied to that particular digest:</p>
<p><pre class="brush:perl; first-line:32">
    my $sha256 = Digest-&gt;new(&quot;SHA-256&quot;);
    if (open my $handle, $name) {
      $sha256-&gt;addfile($handle);
      my $digest = $sha256-&gt;hexdigest;
</pre></p>
<p>That <code>hexdigest</code> call is important, and one of the issues that I usually forget. The digest by itself is just a big number. To turn it into what I usually expect, a string of hexadecimal digits, I call the right method. The <code>digest</code>  method returns a binary string. I could have used <code>b64digest</code> to get a Base-64 encoded version.</p>
<p><a href="http://www.learning-perl.com/?p=286#comment-1233">On his next go around</a>, he moved those details higher in the program, making way for an eventual configuration outside the program:</p>
<p><pre class="brush:perl; first-line:11">
my $algorithm = &#039;SHA-256&#039;;
</pre></p>
<p><pre class="brush:perl; first-line:27">
        my $digest = Digest-&gt;new($algorithm);
</pre></p>
<p>Most people reached directly for either <a href="https://www.metacpan.org/module/Digest::MD5">Digest::MD5</a> or <a href="https://www.metacpan.org/module/Digest::SHA1">Digest::SHA1</a>, both which export functions for these:</p>
<p><a href="http://www.learning-perl.com/?p=286#comment-998">Jack Maney put his digest details in a subroutine</a>, which compartmentalizes them in a part the rest of the program doesn&#8217;t need to know about. If he wants to change the digest, he changes the subroutine:</p>
<p><pre class="brush:perl; first-line:118">
sub compare_files
{
    my ($file1,$file2)=@_;
 
    if($line_by_line) #using File::Compare::compare
    {
        my $ret_val=eval{compare($file1,$file2)};
 
        die &quot;File::Compare::compare encountered an error: &quot; . $@ if $@;
 
        return 1 if $ret_val==0; #compare() returns 0 if the files are the same...
 
        return undef;
    }
    else #Otherwise, we use Digest::SHA1.
    {
        open(my $fh1,&quot;&lt; &quot;,$file1) or die $!;
        open(my $fh2,&quot;&lt;&quot;,$file2) or die $!;
 
        my $sha1=Digest::SHA1-&gt;new;
 
        $sha1-&gt;addfile($fh1); #Reads file.
        my $hex1=$sha1-&gt;hexdigest; #40 byte hex string.
 
        $sha1-&gt;reset;
        $sha1-&gt;addfile($fh2);
        my $hex2=$sha1-&gt;hexdigest;
 
        close($fh1);
        close($fh2);
 
        return $hex1 eq $hex2;
    }
}
</pre></p>
<p>Tudor went for Digest::MD5, which exports <code>md5_hex</code>. I don&#8217;t particularly like this function because I always think it should take a filename. Tudor uses <A href="https://www.metacpan.org/module/File::Slurp">File::Slurp</a>&#8216;s <code>read_file</code> Instead I have to give it the actual file contents. Tudor has a bit of a problem because he does the computation twice for each file:</p>
<p><pre class="brush:perl; first-line:27">
        my $file_content = read_file( $file_name, binmode =&gt; &#039;:raw&#039; );
        if ( defined($duplicate_files-&gt;{ md5_hex( $file_content ) }) ){
            push @{ $duplicate_files-&gt;{ md5_hex( $file_content ) } }, $file_name;
        } else {
            $duplicate_files-&gt;{ md5_hex( $file_content ) } = [ $file_name ];
        };
</pre></p>
<p><A href="http://www.learning-perl.com/?p=286#comment-1097">Ulrich does the same thing</a>, but does the computation once and stores it in a variable:</p>
<p><pre class="brush:perl; first-line:19">
  my $digest=md5_hex();
  if (exists $filehashes{$digest}) {
    $dupfree=0;
    push @{$filehashes{$digest}}, $file;
    print &quot;duplicates detected: &quot;;
    foreach $file (@{$filehashes{$digest}}) {
      print &quot;$file  &quot;;
    }
</pre></p>
<p>Instead of Digest::MD5, <a href="http://www.learning-perl.com/?p=286#comment-1213">Gustavo used</a> <a href="https://www.metacpan.org/module/Digest::SHA1">Digest::SHA1</a>, which has a similar interface . He wraps it all up in a single statement:</p>
<p><pre class="brush:perl; first-line:23">
    push @{$sha2files{sha1_hex(read_file($file))}}, $file;
</pre></p>
<p><a href="">Mr. Nicholas did the same</a> with <a href="https://www.metacpan.org/module/Digest::MD5">Digest::MD5</a>:</p>
<p><pre class="brush:perl; first-line:9">
    push @{$data{md5_hex(read_file($_))}},$_ if -f $_;
</pre></p>
<p><A href="http://www.learning-perl.com/?p=286#comment-1285">Javier  used the object form</a> of <a href="https://www.metacpan.org/module/Digest::MD5">Digest::MD5</a> that takes a filehandle. He has a subroutine that just returns the digest:</p>
<p><pre class="brush:perl; start-line:15">
sub get_hash($)
{
   open(FILE, $_);
   return Digest::MD5-&gt;new-&gt;addfile(*FILE)-&gt;hexdigest;
}
</pre></p>
<p><a href="http://www.learning-perl.com/?p=286#comment-1285">Eric also used the object form</a>, but used the module directly in the statement:</p>
<p><pre class="brush:perl; start-line:21">
    $fp{$_} = Digest::MD5-&gt;new-&gt;addfile(*FILE)-&gt;hexdigest;
</pre></p>
<p>The winner for this part of the problem would have to be a tie between Anonymous Coward setting up a flexible digest system and Javier for creating a short subroutine. Anonymous Coward comes out slightly ahead I think.</p>
<h3>Finding duplicates</h3>
<p>Finding the duplicates is the final part of the problem. Most answers did what <a href="http://www.learning-perl.com/?p=286#comment-979">Anonymous Coward did</a>. When he computed a digest, he used it as the key in a hash, and made the value an array reference. In his first go, he uses the v5.14 feature that automatically dereferences the first argument to push:</p>
<p><pre class="brush:perl; start-line:37">
      if (exists $duplicates{$digest}) {
        push $duplicates{$digest}, $name;
      } else {
        $duplicates{$digest} = [$name];
      }
</pre></p>
<p>Jack Maney used Set::Scalar to keep track of duplicates. He goes through the list of files and compares them with every other file in a double <code>foreach</code> loop, which is a lot of work. If the two files are the same, he looks through all the sets he&#8217;s stored so far looking for a set that already contains one of the filenames so he can add the new filename:</p>
<p><pre class="brush:perl; start-line:60">
foreach my $file1(@files)
{
  foreach my $file2(@files)
  {
    next if $file1 eq $file2; #only comparing distinct pairs of files!

    if(compare_files($file1,$file2)) #If they&#039;re the same...
    {
      #first, see if $file1 is in any element of @duplicates.
      my $found=0; #flag to see if we found $file1 or $file2

      foreach my $set (@duplicates)
      {
        if($set-&gt;has($file1))
        {
          $set-&gt;insert($file2);
          $found=1;
          last;
        }
        elsif($set-&gt;has($file2))
        {
          $set-&gt;insert($file1);
          $found=1;
          last;
        }
      }

      unless($found) #If we didn&#039;t find $file1 or $file2 in @duplicates, add a new set!
      {
        push @duplicates,Set::Scalar-&gt;new($file1,$file2);
      }
    }
  }
}
</pre></p>
<p>There are some good ideas there, but I&#8217;d have to revert to references to improve it by keeping the sets as values in a hash where the key is the digest. However, I&#8217;m limiting myself to whatever we have in <i>Learning Perl</i> for my official solution. For my unofficial solution, I would have made a single pass over <code>@files</code> to digest it and another pass over <code>%digests</code> to report them:</p>
<p><pre class="brush:perl">
foreach my $file ( @files ) {
  my $digest = get_digest( $file );
  $digests{$digest} = Set::Scalar-&gt;new 
    unless defined $digests{$digest};
  $digests{$digest}-&gt;insert( $file );
  }
  
foreach my $digest ( keys %digests ) {
  next unless $digests{$digest}-&gt;size &gt; 1;
  my $dupes = $digests{$digest}-&gt;members;
  }
</pre></p>
<p>Most everyone did the same thing, so points go to Anonymous Coward for getting their first.</p>
<h2>The results</h2>
<p>I&#8217;m not assigning a winner to first part that involved finding files. Anonymous Coward wins the second part by setting up his digest to be flexible through <A href="https://www.metacpan.org/module/Digest">Digest</a>&#8216;s interface. Anonymous Coward narrowly pips the other solutions for reporting the duplicates because he was first, since most people used a hash with array references for values.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D317" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=317&amp;t=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=317&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29&amp;body=Link:+http://www.learning-perl.com/?p=317%0D%0A%0D%0A----%0D%0A+March%27s+challenge+was+to+find+duplicate+files.+I+often+write+a+quick+and+dirty+program+to+do+this%2C+having+forgotten+what+I+called+the+program+or+ha..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29&amp;summary=March%27s+challenge+was+to+find+duplicate+files.+I+often+write+a+quick+and+dirty+program+to+do+this%2C+having+forgotten+what+I+called+the+program+or+ha...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=317&amp;title=Learning+Perl+Challenge%3A+finding+duplicates+%28Answer%29" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=317" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=317</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Learning Perl Challenge: tripwire</title>
		<link>http://www.learning-perl.com/?p=287</link>
		<comments>http://www.learning-perl.com/?p=287#comments</comments>
		<pubDate>Sun, 15 Apr 2012 02:12:06 +0000</pubDate>
		<dc:creator>brian d foy</dc:creator>
				<category><![CDATA[Challenges]]></category>

		<guid isPermaLink="false">http://www.learning-perl.com/?p=287</guid>
		<description><![CDATA[The previous Learning Perl Challenge asked you to find duplicate files. This challenge needs some of which you did there, but for a different purpose. Write a program that monitors a directory to find any file changes. Programs such as tripwire do this by recording meta information about a file on its first run then [...]]]></description>
			<content:encoded><![CDATA[<p>The previous <a href="http://www.learning-perl.com/?p=286">Learning Perl Challenge</a> asked you to find duplicate files. This challenge needs some of which you did there, but for a different purpose.</p>
<p>Write a program that monitors a directory to find any file changes. Programs such as <a href="http://sourceforge.net/projects/tripwire/">tripwire</a> do this by recording meta information about a file on its first run then checking that the same information matches later. For instance, the size and SHA1 digest should stay the same. You could also just store the original content, but that&#8217;s not very convenient.</p>
<p>Since you&#8217;re at the <i>Learning Perl</i> level, we can&#8217;t ask too much here or judge you too harshly. A lot of the problem is storing the data and reading it later. Here&#8217;s a hint: create a flat file to store the &#8220;good&#8221; data on the first run, then read this file on the second run:</p>
<p><pre class="brush:plain">
#name:size:SHA1
file.txt:1023:53a0935982ae11a4784d51aa696733c947c0614f
</pre></p>
<p>How are you going to handle the security on this file after you create it? As an example, you might look at <a href="https://www.metacpan.org/module/CPAN::Checksums">CPAN::Checksums</a>, which handles the same task for the modules on CPAN.</p>
<p>There are many ways that you can employ use this. You can run it periodically from cron, for instance, but you might also make a daemon that runs continually and is always checking. Once you find a change, you can report it in many ways, but we&#8217;ll only ask you to print a line to the terminal, that might look something like:</p>
<p><pre class="brush:plain">
file.txt changed.

Was:
Size: 1023 bytes
SHA1: 53a0935982ae11a4784d51aa696733c947c0614f

Is now:
Size: 2001 bytes
SHA1: 730c6983bb9f942ef5cf6c174d76ad0c1594c1a7
</pre></p>
<p>You can see <A href="http://www.learning-perl.com/?page_id=289">a list of all Challenges and my summaries</a> as well as the programs that I created and put in the <a href="https://github.com/briandfoy/learning-perl-challenges<br />
">Learning Perl Challenges</a> GitHub repository.</p>
<div class="tweetthis" style="text-align:left;"><p> <a target="_blank" rel="nofollow" class="tt" href="http://twitter.com/home/?status=Learning+Perl+Challenge%3A+tripwire+http%3A%2F%2Flearning-perl.com%2F%3Fp%3D287" title="Post to Twitter"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://delicious.com/post?url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire" title="Post to Delicious"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://digg.com/submit?url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire" title="Post to Digg"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.facebook.com/share.php?u=http://www.learning-perl.com/?p=287&amp;t=Learning+Perl+Challenge%3A+tripwire" title="Post to Facebook"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.google.com/buzz/post?url=http://www.learning-perl.com/?p=287&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a target="_blank" rel="nofollow" class="tt" href="https://mail.google.com/mail/?ui=2&amp;view=cm&amp;fs=1&amp;tf=1&amp;su=Learning+Perl+Challenge%3A+tripwire&amp;body=Link:+http://www.learning-perl.com/?p=287%0D%0A%0D%0A----%0D%0A+The+previous+Learning+Perl+Challenge+asked+you+to+find+duplicate+files.+This+challenge+needs+some+of+which+you+did+there%2C+but+for+a+different+purpo..." title="Send Gmail"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/gmail/tt-gmail.png" alt="Send Gmail" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire&amp;summary=The+previous+Learning+Perl+Challenge+asked+you+to+find+duplicate+files.+This+challenge+needs+some+of+which+you+did+there%2C+but+for+a+different+purpo...&amp;source=Learning Perl" title="Post to LinkedIn"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/linkedin/tt-linkedin.png" alt="Post to LinkedIn" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://reddit.com/submit?url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire" title="Post to Reddit"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire" title="Post to Slashdot"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://stumbleupon.com/submit?url=http://www.learning-perl.com/?p=287&amp;title=Learning+Perl+Challenge%3A+tripwire" title="Post to StumbleUpon"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a target="_blank" rel="nofollow" class="tt" href="http://technorati.com/faves?add=http://www.learning-perl.com/?p=287" title="Post to Technorati"><img class="nothumb" src="http://www.learning-perl.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.learning-perl.com/?feed=rss2&amp;p=287</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
