in reply to Loop Control

Hey guys, thanks so much for the productive feedback! Im still very much a newbie with lots to learn. So far I am enjoying my inductance to the monastary very much :) Also, I apologize if the code didn't run. Thats what I get for copying and pasting selective statements from my original... oh well. Also, I know it seems like a lot of work for printing subdirectories, but the reason I went throught the trouble is because I wanted to manipulate the strings in such a way as so that I could eventually populate these strings into a separate array, and then pass them to the shell to perform commands on. After doing some reading, I finally figured out that the c-like for loop is the answer to what I was looking for. Here is what my real code looks like now:
#!/bin/perl use strict; use warnings; sub newl { print "\n"; print "\n"; } my @a; my @b; my @c; my @d; my @e; my $na; my @Na; #@a = `df -h | grep mapper | cut -c 48-`; # My original code uses the above statement, but because # this may look different on different shells, I used the # array below @a = ( "/", "/home", "/var", "/tmp", "/var/tmp", "/boot" ) $na = $#a; @Na = ( 0, 1..$na ); for my $i (@Na) { $b[$i] = `ls $a[$i]`; } print @a; newl; for my $i (@Na) { print "\$b[$i] = $b[$i]"; newl; } for (my $i = 0; $i < 1; $i++ ) { my @c1 = split ("\n", $b[$i]); my $nc = $#c1; for (my $w = 0; $w <= $nc; $w++ ) { my $z0; my $z1; my $z2; $z0 = $a[$i]; chomp $z0; $z1 = $c1[$w]; $z2 = $z0 . $z1; #print $z2; newl; push (@c, $z2); }} for (my $i = 1; $i <= 5; $i++ ) { my @c1; @c1 = split ("\n", $b[$i]); my $nc = $#c1; for (my $w = 0; $w <= $nc; $w++ ) { my $z0; my $z1; my $z2; $z0 = "$a[$i]"; chomp $z0; $z1 = "\/$c1[$w]"; $z2 = $z0 . $z1; #print $z2; newl; push (@c, $z2); }} print "\$#c = $#c"; newl; for (my $i = 0; $i <= $#c; $i++ ) { my $y = `du -B MB -d0 $c[$i]`; push (@d, $y); } print "\$#d = $#d"; newl; for (my $i = 0; $i <= $#d; $i++ ) { print "$d[$i]"; newl; } for (my $i = 0; $i < 1; $i++ ) { my @c1 = split ("\n", $b[$i]); my $nc = $#c1; for (my $w = 0; $w <= $nc; $w++ ) { my $z0; my $z1; my $z2; $z0 = $a[$i]; chomp $z0; $z1 = $c1[$w]; $z2 = `ls -last $z0 | grep $z1`; chomp $z2; push (@e, $z2); }} for (my $i = 1; $i <= 5; $i++ ) { my @c1; @c1 = split ("\n", $b[$i]); my $nc = $#c1; for (my $w = 0; $w <= $nc; $w++ ) { my $z0; my $z1; my $z2; $z0 = "$a[$i]"; chomp $z0; $z1 = "$c1[$w]"; $z2 = `ls -last $z0 | grep $z1`; chomp $z2; push (@e, $z2); }} print "\$#e = $#e"; newl; for (my $i = 0; $i <= $#e; $i++ ) { print "$e[$i]"; newl; }
Basically this is my attempt to create a perl script to list size and usage data on subdirectories in my system. This is the template script, my goal is to use Text::CSV to output the data in the arrays @c, @d, & @e into a csv file. Now that I got my first part working, I can go onto part two! I had such a hard time intitially, becuase I was using the output from du -B MB, which would just create variable length strings. If I wanted to I guess I could go that route, but I figured I'd just set the max-depth to 0, to get the values only for the directory i'm evaluating. I know this is a *nix oriented script, eventually I'd like to create something like this to run on windowz. :)

Replies are listed 'Best First'.
Re^2: Loop Control
by xyzzy (Pilgrim) on Jul 06, 2012 at 02:03 UTC

    Here are some pointers to help you assimilate to a more Perlish way of thinking (RESISTANCE IS FUTILE)

    • I can see the point of the newl() subroutine if you want to be able to globally change what is printed after each thing of interest, but here are some ways you can make it look nicer:
      • The most obvious is combine the two prints into print "\n\n";
      • Since you seem to always use it immediately after a print statement, why not just declare it as a variable? $NEWL="\n\n"; print "Pass it after the string like so", $NEWL; print "Or you can just interpolate$NEWL"
      • If you read through perlvar, you will find a section about $\, the output record separator. This is a special variable that is printed after every print statement. Instead of making a call to newl every time, just let Perl do all the work. local $\ = "\n\n"; print "No more newls!" You can always unset it with undef $\;
    • my (and similar operators like our and local) can be applied to any number of variables at once: my (@a, @b, @c, @d, @e);. You can even assign things this way: my ($z1, $z2) = ($a[$i],$c1[$w]);
    • assignment returns the lvalue (not the rvalue!), which means chomp(my $a = $b); is equivalent to my $a = $b;chomp $a;
    • the range operator can use any integer (or even string) values, providing the left one is smaller than the right. (0, 1..$n) can be written as (0..$n) with no ill effects.
    • qw// is often preferred when making lists of strings that do not contain spaces. Like most operators in the quote-like family, you can use any delimiters you want: @a = qw(/ /home /var /tmp /var/tmp)
    • Off the top of my head, I can't think of an instance where $a = $b would give a different result than $a = "$b". I'm sure someone out there knows enough voodoo to provide some rare case where the latter would be preferred (perhaps if you were overloading stringification?), but in general Perl doesn't care if the scalar you give it is a number of a string because it will convert freely between the two. Maybe if you wanted to clean up a number stored as a string you could do something like $a = "05.230000"; $b = $a+0; # $b is 5.23 (number), but interpolating variables by themselves is a little redundant.

    There are other things that could be greatly simplified as well, but those are just some of the more critical stylistic faux pas that jumped out at me. Honestly, if your code works exactly as expected, then there's not really anything wrong with it :) And if you can understand why and how it works, then it's Good Enough(tm). When I was just starting out with Perl, map confused the hell out of me, so I never used it and I always avoided solutions that people gave me that used it. Then when it clicked I thought "Holy llama balls, this shit is The Shit" and tried using it for everything. Neither ways are necessarily the best approach. In the end, all that matters is that you're constantly learning how and when to use the unique features of Perl that make it so slackfully elegant. Just lurk around and look at code examples passed around and you'll start to get it.

    But seriously, do some experimenting with map, because it will greatly simplify any operation where you have to turn one set of values into another.


    $,=qq.\n.;print q.\/\/____\/.,q./\ \ / / \\.,q.    /_/__.,q..
    Happy, sober, smart: pick two.
      Off the top of my head, I can't think of an instance where $a = $b would give a different result than $a = "$b".
      This will explode horribly if $b is a reference. Compare the following:
      [ateague@dingbat mod]$ perl -MData::Dumper -E '$b = [qw/1 2 3 4 5/]; $ +a = $b; say Dumper $a;' $VAR1 = [ '1', '2', '3', '4', '5' ]; [ateague@dingbat mod]$ perl -MData::Dumper -E '$b = [qw/1 2 3 4 5/]; $ +a = qq|$b|; say Dumper $a;' $VAR1 = 'ARRAY(0x12609e4)';
      The first one prints the array referenced by the reference. The second one simply prints a string containing the memory address of the array reference.