Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

How to avoid "Use of uninitialized value" with printf?

by bobdabuilda (Sexton)
on Apr 05, 2012 at 06:10 UTC ( #963594=perlquestion: print w/ replies, xml ) Need Help??
bobdabuilda has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys. Have been working on a bit of a toy utility for myself to fill in a bit of downtime. Part of it involves interrogating a system, and dumping to screen a list of values, in column format.

A snippet of the code I'm using is shown below:

my @UACS; # open(POLICY, "getpol -t UACS |"); commented - replaced by __DATA_ +_ for this example my $pol; while (<DATA>) # ($pol = <POLICY>) <== could this be changed to wh +ile (my $pol = <POLICY>), to remove the previous line ?? { chomp $_; # was $pol my($type,$number,$name); ($type, $number, $name) = split (/\|/, $_, -1); chomp $name; push(@UACS,$name); } @UACS = sort(@UACS); while (@UACS) { my @rows = splice(@UACS, 0, 6); printf "%-12s %-12s %-12s %-12s %-12s %-12s\n", @rows; } print "\nPress ENTER to continue..."; my $a = <STDIN>; # close(POLICY); commented - superfluous due to __DATA__ for this e +xample __DATA__ UAC|10|ADMIN|Description1| UAC|20|CIRC|Description2| UAC|30|CIRCADMIN|Description3| UAC|40|CIRCBEE|Description4| UAC|50|CIRCBRO|Description5| UAC|60|CIRCBUR|Description6| UAC|70|CIRCBUW|Description7| UAC|80|CIRCCAS|Description8| UAC|90|CIRCCOM|Description9|

Now, whilst manipulating and testing the above to get it runnable for display here, I *may* have realised part of what the issue is... but there's still a ?? around part of it.

I'm thinking that, where the script is splitting the data, effectively, into rows of 6... when there aren't 6 items - as per the above example, on the second pass - it gives 3 instances of the "Use of uninitilized value in printf" error - which with this example equate to the 3 values that aren't there for the printf command on the second pass.

Sounds right so far, yeah? The only problem I have at this point, is that when running it with the full set of data, it gets around 90% of the way through, dumps out 4 of those errors, and then prints 2 more values at the end... which kind of blows my theory out of the water...

However - on having another look at the results, the 4 errors being spat out are after a "complete" line is printed, followed by the last 2 values. That equals 6 items, which is how many it's trying to print. Is printf somehow filling the %-12s from right to left for some reason, perhaps??

Please help me demistify this issue...

Comment on How to avoid "Use of uninitialized value" with printf?
Select or Download Code
Re: How to avoid "Use of uninitialized value" with printf?
by Anonymous Monk on Apr 05, 2012 at 06:45 UTC

    :) Please don't describe things your posted code doesn't demonstrate :)

    You pretty much right about what happens, you can disable those warnings with  no warnings q{uninitialized};

    $ perl -le " use strict; use warnings; printf qq{%-12s %-12s\n}, @ARGV + " Missing argument in printf at -e line 1. Missing argument in printf at -e line 1. $ perl -le " use strict; use warnings; printf qq{%-12s %-12s\n}, @ARGV + " what Missing argument in printf at -e line 1. what $ perl -le " use strict; use warnings; printf qq{%-12s %-12s\n}, @ARGV + " what what what what $ perl -le " use strict; use warnings; use diagnostics; printf qq{%-12 +s %-12s\n}, @ARGV " Missing argument in printf at -e line 1 (#1) (W uninitialized) A printf-type format required more arguments tha +n were supplied. $ perl -le " use strict; use warnings; no warnings q{uninitialized}; p +rintf qq{%-12s %-12s\n}, @ARGV " $ perl -le " use strict; use warnings; no warnings q{uninitialized}; p +rintf qq{%-12s %-12s\n}, @ARGV " oh oh $ perl -le " use strict; use warnings; no warnings q{uninitialized}; p +rintf qq{%-12s %-12s\n}, @ARGV " oh yeah oh yeah

      Thanks for the response, Anon. One question for you - when in a position to not provide the original data you are working with... how, exactly, is one supposed to formulate a question?

      I did what I thought was the best solution to this, which was to post up some working code, with an example of equivalent data, combined with an explanation of the symptoms I am seeing. The code snippet was kept the same as the original, aside from the lines I commented out (rather than simply deleting them, for visibility, in case there was an issue with the way those lines were being used).

      Please tell me how I could have presented my question better/more clearly so that I can ensure I do so in future?

        Please tell me how I could have presented my question better/more clearly so that I can ensure I do so in future?

        :) Yeah, I probably should not have lead with that comment, not that I remember , nor can I even guess what I was referring to. Your question is very well presented (practically perfect). Mea culpa.

        Are you clear on the issue of the warning?

        Here is another way with Perl6::Form ( also documented at http://search.cpan.org/dist/Perl6-Doc/share/Exegesis/E07.pod ) based on demo_columns

        the more verbose version

        use Perl6::Form; print form {layout=>"across"}, '{:[{10}]:} {:[{10}]:} {:[{10}]:} {:[{10}]:} {:[{10}]:} {:[{10}]:} ', \@UACS , \@UACS , \@UACS , \@UACS , \@UACS , \@UACS ;

        or the same thing using the repeat operator

        use Perl6::Form; print form {layout=>"across"}, '{:[{10}]:} ' x 6 , ( \@UACS ) x 6;

        Place either right after  @UACS = sort(@UACS); , no splicing required, and @UACS remains full afterwards

Re: How to avoid "Use of uninitialized value" with printf?
by Not_a_Number (Parson) on Apr 05, 2012 at 06:49 UTC

    You could change your printf line to:

    printf "%-12s " x @rows, @rows; print "\n";

      Thanks for that! Looks much neater, I'll check it out.

Re: How to avoid "Use of uninitialized value" with printf?
by GrandFather (Cardinal) on Apr 05, 2012 at 07:33 UTC

    Strings sent to STDERR (as from die or warnings) are interspersed with strings sent to STDOUT so errors and normal text may not be shown in the order that they are created. Very often error and warning messages are shown before the normal text that was generated around the time the error occurred.

    One way to clean the issue up in this case is:

    print join (' ', map {sprintf '%-12s', $_} @rows), "\n";

    There are many other ways of course.

    True laziness is hard work

      GrandFather, thanks for the explanation and suggested fix. I'll take a look and do some reading up on the "print join" thing to work out how it works, then have a play with it in my code once I've sussed it out.

      I much prefer the option of avoiding the cause of the warnings, rather than simply suppressing them... never know what you're missing out on in the way of warnings you SHOULD be getting :)

        There are a number of interesting parts to that statement. The sprintf is just a printf that returns a string instead of sending it to a file.

        map processes lists. The expression inside the map is evaluated for each element in the list in turn with $_ aliased to the current element. A list containing the result of evaluating the expression for each element is returned by map.

        join just glues elements in a list together using the first string as glue.

        True laziness is hard work

        In this case, you (now) know that missing or undefined values (for the format string) are the cause of the warnings. Then, why not mute them for the relevant code for there is nothing else to "[miss] out on"?

        ... { no warnings 'uninitialized'; printf $format , @values; } ...

        Since missing values do not matter, both Not_a_Number's and Grandfather's suggestion will work equally.

        In case one would need to show the values under proper column headings, then you would need to fill in the missing or undefined values with substitute values (empty string, 0, -, N/A, /, etc). That may also call for the data to be properly formatted such that missing values are represented by their absence.

        Just wanted to report back to advise that I've now got this aspect of things working the way I wanted, with your help.

        I've also gone back over my code and tidied things up a bit and removed some of the superfluous variables I was using for reading in files, and gone back to using the default $_, which made things neater and has helped me to work out a couple other kinks.

        So, thanks again one and all for your assistance and suggestions :)

Re: How to avoid "Use of uninitialized value" with printf?
by Anonymous Monk on Apr 11, 2012 at 07:57 UTC

    # open(POLICY, "getpol -t UACS |"); commented - replaced by __DATA_ +_ for this example my $pol; while (<DATA>) # ($pol = <POLICY>) <== could this be changed to wh +ile (my $pol = <POLICY>), to remove the previous line ?? { ... } ...

    Yes, you have the correct syntax, for getting a line from the file handle, in the comment above.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://963594]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2014-09-21 00:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (165 votes), past polls