On Tue, Sep 8, 2009 at 11:41 AM, Palit,
Nilanjan<[email protected]> wrote:
>
> http://blogs.discovery.com/nerdabout_new_york/2009/08/perl-puzzler.html#comments

The puzzle is to explain how this works:

  cksum file1 file_n | perl -ane 'warn if $F[0] != ($x ||= $F[0])'

I'm sick and bored today, so here goes. :)

cksum <file_1> <file_n> produces output like this:

  <hash> <bytes> <filename>

One line like this is output for each file specified on the command line.

These lines are then piped into the perl command.

perl -e '<perl code>' is pretty self explanitory - it runs the code
between the quotes.

perl -ne '<perl code>' adds some convenience, wrapping the code in a
'while( <> ) { ... }' loop, where ... is your code.

This means the specified code will be looped over for each line of
input. In this case, the input to perl is the output from the cksum
command.

perl -a is another convenience shortcut, called 'autosplit'. It
inserts the code '@F = split(' ');' before your code, so that @F
contains the split-out fields from the input to your program.

When -a is combined with -n, think of it being inserted as the first
statement in the while loop. Like this...

while( <> ) { @F = split(' '); ... }

Again, ... is your code, in this case the code specified after the -e.

So, think about the perl code as having this extra stuff around it and
it begins to come clear: Each line of output from cksum gets split
into @F. What the perl code really looks like is this:

while( <> ) {
  @F = split(' ');
  warn if $F[0] != ($x ||= $F[0])
}


Now we need to figure out what the code from the -e is doing. This
code is being run without strict and without warnings. Keep that in
mind...

It seems we only care about the first element in @F, since the code
only looks at $F[0]. Given the output of cksum, this is just the hash
of the current file. No matter what name a file has, if it's contents
are the same, it will have the same hash. Remember that.

Each time through the loop, @F is populated with a line of output from
cksum, a line for each file. What about $x? We're not using strictures
so $x is autovivified the first time through the loop, and treated as
a 'global' (perl experts know why I put global in quotes)

Furthermore, $x is only assigned to if it's value is false, because
we're using the ||= operator. This means $x is assigned the value of
$F[0] the first time through the loop... and after that it's value is
no longer false!

*** $x only ever contains the hash for the *first* file given to cksum! ***

One last piece to make this all clear: the result of the expression
($x ||= $F[0]) is always the value of $x.

Therefore, each iteration through the loop, the code is comparing
$F[0], the current file's hash, to $x, the hash of the first file.

This convoluted little script is just a simplistic (and potientially
buggy) "diff" utility, that spits out a warning if any files passed to
cksum differ from the first.


-- 
-- Steve Scaffidi <[email protected]>

_______________________________________________
Boston-pm mailing list
[email protected]
http://mail.pm.org/mailman/listinfo/boston-pm

Reply via email to