开发者

How can I use Perl to get a SHA1 hash of a file from the Windows command line?

I have a file called secure.txt in c:\temp. I want to run a Perl c开发者_如何学JAVAommand 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.


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.

With Perl version 5.10 or later, you can shorten the above one-liner by five characters.

perl -MDigest::SHA=sha1_hex -E 'say sha1_hex<>' secure.txt

The code drops the optional (with all versions of Perl) whitespace before <>, drops -l, and switches from -e to -E.

  • -E commandline

    behaves just like -e, except that it implicitly enables all optional features (in the main compilation unit). See feature.

One of those optional features is say, which makes -l unnecessary.

  • say FILEHANDLE LIST

  • say LIST

  • say

    Just like print, but implicitly appends a newline. say LIST is simply an abbreviation for

      { local $\ = "\n"; print LIST }
    

    This keyword is only available when the say feature is enabled: see feature.

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::SHA;

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

foreach my $file (@ARGV) {
  my $sha1 = Digest::SHA->new(1);  # use 1 for SHA1, 256 for SHA256, ...
  $sha1->addfile($file);
  say($sha1->hexdigest, "  $file");
}

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.


Try the Digest::SHA module.

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


As of this writing, both Strawberry Perl and ActiveState Perl include the shasum command that comes with Digest::SHA. If you chose the default options during setup, this will already be in your %PATH%.

If you really, really want to write your own wrapper for Digest::SHA, the other answers here are great.

If you just want to "use Perl" to get the SHA1 hash for a file, in the sense that you have ActiveState Perl, and it comes with the shasum command-line utility, it's as simple as:

shasum secure.txt

The default hashing algorithm is SHA1; add -a1 if you want to be explicit (not a bad idea).

The default output format is the hash, two spaces, then the filename. This is the same format as sha1sum and similar utilities, commonly found on Unix/Linux systems. If redirected into a file, that filename can be given to shasum -c later in order to verify the integrity whatever files you had hashed previously.

If you really, really don't want to see the filename, just the SHA1 hash, either of these will chop off the filename part:

Using Powershell:

shasum secure.txt | %{$_split()[0]}

Using Command Prompt (old-school batch scripting):

for /f %i in ('shasum secure.txt') do echo %i

For the second one, make sure you use %%i instead of %i (both places) if you're putting that in a .cmd or .bat file.


Use Digest::SHA1 like so:

Using the OO strategy:

#!/usr/bin/perl -w
use v5.10; # for 'say'
use strict;

require Digest::SHA1;
my $filename = 'secure.txt';
my $sha1 = Digest::SHA1->new->addfile($filename)->hexdigest;
say $sha1;

Note that calling ->hexdigest causes the object's state to clear, causing the current digest it's calculating to be destroyed. You can re-use the $sha1 object at that point.

You can also use sha1_hex sub on the file contents:

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

use Digest::SHA1 qw/ sha1_hex /;

my $filename = "secure.txt";
# open file
open my $fhi, '<', $filename or die "Cannot open file '$filename' for reading: $!";
# slurp all the file contents
my $file_contents;
{local $/; $file_contents = <$fhi>;}
close $fhi;
print &sha1_hex($file_contents);

Note that you can use Digest::SHA instead, where new() takes the algorithm to use as parameter (e.g. 1 for SHA1, 256 for SHA256, ...):

require Digest::SHA;
my $sha1 = Digest::SHA->new(1)->addfile($filename)->hexdigest();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜