hydo has asked for the wisdom of the Perl Monks concerning the following question:

Heya monks. I'm writing a script to rcp a file from one machine to another and then check the sums after the rcp.
I cant use any modules but the default ones as it takes an act of god/congress/both to get a module installed here. The problem is comparing the files. Here's how i'm doing it now:
#this is hp-ux btw...
my $local_compare="/usr/bin/chksum $file";
my $remote_compare="rexec $host -l $user \"/usr/bin/chksum $file\"";

my $g=`$local_compare`;
my $h=`$remote_compare`;

# output of cksum on hockey-pux looks like
# [num] [num] [filename]
my @gg = split( ' ', $g );
my @hh = split( ' ', $h );
if ( $gg[ 0 ] != @hh[ 0 ] ) { 
die( "files do not match.\n" );
I'm sure that there is a better way to do this. Any suggestions?

Also as a side note, I have found myself lately using ? : profusely. I haven't seen this too much in other peoples code lately but mine is littered with them. An example:

my $a = some_func();
$a ? do_something() : do_somethingelse();
This isn't like goto in C is it? I like it because it is compact and looks pretty cool compared to if()/else. Just want to make sure that it's not one of those "That's a really bad idea" things.

Thanks in advance for any and all criticism/tips/crap/etc.

  • Comment on Comparing checksums of local/remote files.

Replies are listed 'Best First'.
Re: Comparing checksums of local/remote files.
by fundflow (Chaplain) on Aug 30, 2000 at 22:51 UTC
    Did you look at 'rsync'?

    It will do what you want and more, while saving bandwidth.

    Recently i use it to synchronize my laptop with anything else.

    There is no real need for installation, but you need to have the executable in each machine. It works on most platrofms (unix/win)
      Yea, I know about it but the problem is that I cannot have ANYTHING installed on these machines. The administration is (*uugh*) outsourced. I'm still waiting on getting DBI installed on one of the devel machines. Suck!
        ...On the same line of thought:

        If you still want to use rsync, then you can have your script copy it over on /tmp and run it from there.

        On Solaris it takes 200k and on linux 135k, so it's not a big deal.

        Needless to say, it would still be nice to have a similar perlish method :)
Re: Comparing checksums of local/remote files.
by gnat (Beadle) on Aug 31, 2000 at 00:48 UTC
    At one level, your question is basically "I want to do something that's best done by existing software, only I can't install it" and the obvious answer is "well, fix whatever management or admin problem is preventing you from installing it".

    I have no comments about the way you're checksumming or rexecing. That looks reasonable to me (although you don't check for errors in $?).

    However, I can help you with Perl ...

    I hate those uses of the hook. That's something that should be an if() in my books, even though it's more typing for you. Not to mention that the precedence of ?: will bugger you up:

    $a % 2 ? $a += 10 : $a *= 2 ($a % 2 ? $a += 10 : $a) *= 2 # what it really is
    Surprise. However, in all honesty, for things where precedence isn't an issue, it's a personal preference style matter. My tastes are to use ?: for picking between values, and if() for picking between bits of code.

    Try this to remove the arrays:

    my ($gg) = split ' ', $g; my ($hh) = split ' ', $h;
    This makes use of the list context caused by the parentheses around $gg and $hh (without the parentheses you'd end up storing the number of fields in $gg rather than the first field), as well as the fact that split does no more work than it has to. If you're assigning to one item, it'll only split up to the first item.

    Hope this helps,


(jeffa) Re: Comparing checksums of local/remote files.
by jeffa (Bishop) on Aug 30, 2000 at 22:41 UTC
    Ternary (or hook) operators rule. Some people don't like
    them, but they generally don't like perl anyways. I say
    use the heck out of 'em. As for GOTO in C, well, C and
    C++ and even Java have ternary operators. Think of it
    as a more consise way of saying if - else.

    Sorry, but I don't have any suggestions for checksums,
    what you have looks good to me.
    I just had to show my appreciation for ? :


Re: Comparing checksums of local/remote files.
by ncw (Friar) on Aug 31, 2000 at 01:00 UTC
    cksum is quite good as checksum algorithms go (it uses a 32 bit CRC AFAIK which is good). md5sum is better but you may not have it installed on the machine - if you do then use that for even more feelgood factor.

    As for your code - you should check the size of the file too as well as the CRC. The CRC has roughly a 1 chance in 2^32 of failing to detect an error. If you constrain that further by checking the length of the file then you'll add several orders of magnitude to that number (depending on the lengths of your files of course).

    # Same to here then my @gg = split /\s+/, $g; my @hh = split /\s+/, $h; die "Files do not match" if $gg[0] != $hh[0] || $gg[1] != $hh[1];
    If you could install a module on the far end then I'd install Digest::MD5 and use that. If you can't install any stuff then what you've got looks pretty good to me.
      hydo, I think you should use Digest::MD5 as suggested by ncw---perhaps you can install your perl modules in some area you have write access to, (your home directory, for example) and add that location to @INC?

      If management sees Perl modules at work (more reliable, maintainable, and faster-to-ship code) then they may well decide to do something about the terrible system administration problems you seem to have.

      Good luck!

Re: Comparing checksums of local/remote files.
by hydo (Monk) on Aug 31, 2000 at 01:43 UTC
    Before someone points it out,
    my $remote_compare="rexec $host -l $user \"/usr/bin/chksum $file\"";
    Should actually be:
    my $remote_compare="rexec $host \"/usr/bin/chksum $file\"";
    In testing, I was prompted for a password whenever I used '-l $user' even if I was running as the same user. Luckily, I am running the script as the same user as $user.