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

This is wtf moment. I am comparing two variables holding integers:
print "[$version_on_disk]\t version on disk\n"; print "[$version_dns]\t version dns\n"; if ( $version_on_disk >= $version_dns ) { print "OK: the $sa_channel version on disk is up to date: $version +_on_disk\n"; exit 0; }
but I get:
[1195873] version on disk [1195874] version dns Argument "^G1195874" isn't numeric in numeric ge Argument "^G1195874" isn't numeric in numeric ge (>=) at kk.pl line 65 +, <CF> line 2.
Why is the second variable not seen as number? This should be quite straightforward according to http://perldoc.perl.org/perlintro.html#Builtin-operators-and-functions

Replies are listed 'Best First'.
Re: Argument isn't numeric in numeric ge
by choroba (Cardinal) on Dec 09, 2011 at 14:07 UTC
    What is this ^G? A bell character? Not a cipher, I think. How do you get the values?
      I do not know where it comes from. The script is a nagios check to monitor the updates.spamassassin.org channel:
      #!/usr/bin/perl use warnings; use strict; use Mail::SpamAssassin; use Net::DNS; # variables my ( $sa_version, $rev_sa_version, $SA, $update_dir, $version_on_disk, $LOCAL_STATE_DIR, $resolver, $query, $version_dns, $sa_channel ); # get the SpamAssassin version from the Perl module $sa_version = Mail::SpamAssassin::Version(); # reverse this number. We will need it for a txt forware query later $rev_sa_version = join(".", reverse split(/\./, $sa_version) ) ; # sa channel we want to monitor $sa_channel = "updates.spamassassin.org"; # get the local state dir update path $LOCAL_STATE_DIR = '/var/lib/spamassassin'; $SA = Mail::SpamAssassin->new( { LOCAL_STATE_DIR => $LOCAL_STATE_DIR, } ); $update_dir = $SA->sed_path('__local_state_dir__/__version__'); # inside $update_dir, get the line starting with "# UPDATE " # save the version in $version_on_disk if ( -e "$update_dir/updates_spamassassin_org.cf" ) { open (CF, "$update_dir/updates_spamassassin_org.cf" ) or die "$!\n +"; while (<CF> ) { last unless /^# UPDATE\s+[A-Za-z]+\s+(\S+)/; $version_on_disk = $1; } } print "$sa_channel channel version on disk is: $version_on_disk\n"; $resolver = Net::DNS::Resolver->new; $query = $resolver->query("$rev_sa_version.$sa_channel", 'txt'); if ( $query ) { for my $rr ( $query->answer ) { $version_dns = $rr->rdata; } } print "$sa_channel channel dns txt query version is $version_dns\n"; print "[$version_on_disk]\t version on disk\n"; print "[$version_dns]\t version dns\n"; if ( "$version_on_disk" >= "$version_dns" ) { print "OK: the $sa_channel version on disk is up to date: $version +_on_disk\n"; exit 0; } else { print "WARNING: there is a newer version available for SpamAssassi +n $sa_channel rules (on disk version is $version_on_disk, new version + is $version_dns. Run sa-update -D as root to upgrade your SpamAssass +in channel version.\n"; exit 1; }
      I added the [] chars around $version_on_disk and $version_dns to make sure no strange characters were coming on the variables. They print correctly on the terminal.

        Specifically use Data::Dumper and $Data::Dumper::Useqq=1;(!!) to see control characters in strings

        I added the [] chars around $version_on_disk and $version_dns to make sure no strange characters were coming on the variables. They print correctly on the terminal.
        How can you detect a sound in brackets? Use Data::Dumper (plus $Data::Dumper::Useqq=1; as advised by jethro) or pipe your output to a hexdump.
        Updated.

        Can you show the content of the file "$update_dir/updates_spamassassin_org.cf" ?

Re: Argument isn't numeric in numeric ge
by JavaFan (Canon) on Dec 09, 2011 at 14:12 UTC
    What makes you think that ^G1195874 should be seen as a number?

      Exactly! ^G1195874 is certainly not a number. Perl is loosely typed but it doesn't mean it should be used in strange ways, like expecting alpha-numeric characters to be treated like numbers.

      You might like to re-consider the two (rather) 'strings' you're trying to compare!

      I understand your point, but when I print it with [] around the variables, it prints without the leading ^G:
      print "[$version_on_disk]\t version on disk\n"; print "[$version_dns]\t version dns\n";
      gives me:
      [1195874] version on disk [1195874] version dns
      So how does that ^G get in front of my variable :?

        The other thing to realize is that a control-G is probably not a printable character. After all, it's supposed to ring a bell (on a teletype) or make some kind of beep noise (on a terminal).

        Try piping your output through od.
Re: Argument isn't numeric in numeric ge
by Marshall (Canon) on Dec 11, 2011 at 09:45 UTC
    Perl provides the C, isprint() function as isPRINT() which tests whether or not a character is printable. http://perldoc.perl.org/perlclib.html#Character-Class-Tests. I would consider using that to filter out these unprintable characters that seem to be messing up the comparison.

    Perhaps using regex:

    #!/usr/bin/perl -w use strict; my $version_on_disk = "\aabfd\nadsf\n\n555"; my $version_dns ="lkjh\a\n\r\n\a89"; foreach ($version_on_disk, $version_dns) { $_ =~ s/[^[:print:]]//g; #delete non-printable chars } print "$version_on_disk $version_dns\n"; #prints: abfdadsf555 lkjh89