views:

240

answers:

3

I have a file called secure.txt in c:\temp. I want to run a Perl command from the command line to print the SHA1 hash of secure.txt. I'm using ActivePerl 5.8.2. I have not used Perl before, but it's the most convenient option available right now.

+14  A: 
perl -MDigest::SHA1=sha1_hex -le "print sha1_hex <>" secure.txt

The command-line options to Perl are documented in perlrun. Going from left to right in the above command:

  • -MDigest::SHA1=sha1_hex loads the Digest::SHA1 module at compile time and imports sha1_hex, which gives the digest in hexadecimal form.
  • -l automatically adds a newline to the end of any print
  • -e introduces Perl code to be executed

The funny-looking diamond is a special case of Perl's readline operator:

The null filehandle <> is special: it can be used to emulate the behavior of sed and awk. Input from <> comes either from standard input, or from each file listed on the command line. Here's how it works: the first time <> is evaluated, the @ARGV array is checked, and if it is empty, $ARGV[0] is set to "-", which when opened gives you standard input. The @ARGV array is then processed as a list of filenames.

Because secure.txt is the only file named on the command line, its contents become the argument to sha1_hex.

If you'd like to have this code in a convenient utility, say mysha1sum.pl, then use

#! /usr/bin/perl

use warnings;
use strict;

use Digest::SHA1;

die "Usage: $0 file ..\n" unless @ARGV;

foreach my $file (@ARGV) {
  my $fh;
  unless (open $fh, $file) {
    warn "$0: open $file: $!";
    next;
  }

  my $sha1 = Digest::SHA1->new;
  $sha1->addfile($fh);
  print $sha1->hexdigest, "  $file\n";

  close $fh;
}

This will compute a digest for each file named on the command line, and the output format is compatible with that of the Unix sha1sum utility.

C:\> mysha1sum.pl mysha1sum.pl mysha1sum.pl 
8f3a7288f1697b172820ef6be0a296560bc13bae  mysha1sum.pl
8f3a7288f1697b172820ef6be0a296560bc13bae  mysha1sum.pl

You didn't say whether you have Cygwin installed, but if you do, sha1sum is part of the coreutils package.

Greg Bacon
+1 for Perl Golf hole-in-one
amphetamachine
So much information... I'd +2 if I could!
MiffTheFox
Very clear. Just what I needed. Thanks!
Jim
@Jim You're welcome. I'm glad it helps!
Greg Bacon
nit: because secure.txt is the only file, its contents become the argument*S* to sha1_hex (each line a separate argument). As it happens, sha1_hex joins its arguments back together and gives the SHA1 of the whole file, but use of <> other places won't necessarily work that way.
ysth
@ysth Thanks! Fixed.
Greg Bacon
A: 

Use Digest::SHA1 like so:

#!/usr/bin/perl -w
use strict;

use Digest::SHA1    qw/ sha1_hex /;

# open file
open IN_DATA, "<secure.txt" or die "cannot open file secure.txt for reading: $!";
# read in all file contents
my $file_contents;
{local $/; $file_contents = <IN_DATA>;}
# close file
close IN_DATA;
print &sha1_hex($file_contents);

Edit: Why the down vote? Does this code not work? Is this not an appropriate solution to the problem?

amphetamachine
Please use local lexical filehandles - `open my $in_data, '<', 'secure.txt' or die ...`
Ether
@Ether - It's a matter of personal preference.
amphetamachine
There are good reasons to use lexical handles. See http://stackoverflow.com/questions/1479741/why-is-three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice
daotoad
Use good habits even when you don't need to so they stay habits when you do need to. :)
brian d foy
There is a way to do it with out reading the contents of the file yourself.
Brad Gilbert
+2  A: 

Try the Digest::SHA module.

C:\> perl -MDigest::SHA -e "print Digest::SHA->new(1)->addfile('secure.txt')->hexdigest"
Robert Wohlfarth