1

I have a simple question I was hoping you guys can help shed light on. I'm steadily learning perl.

Say I have a very large string, for example take the output of:

our $z = `du -B MB /home`

This will produce a string like the following:

1MB     /home/debug/Music
1MB     /home/debug/Downloads
20MB    /home/debug
20MB    /home/

What I would like to know is, how do I go about loading this string into an array with two columns, and n rows (where n is the number of lines in the du output)?

I was trying something like the following:

my $z1 = `du -B MB /home | tail -4`;
my @c0 = split (/n/, $z1);
my $z2 = join (/\t/, @c0);
my @c2=split(/\t/, $z2);
print @c2;

Which produces the following output:

1MB/home/debug/Music1MB/home/debug/Downloads20MB/home/debug20MB/home

I suppose I can use the substitution function s///g to substitue the directories for null values, and set the SPACE values to one array, and null the space values and set that to a second array, and can set 1 array as keys to the other.

Does anyone have any suggestions as to the best way to approach this?

Any help is appreciated.

Thanks,

Diego

2
  • The first split should be using z1 as the second parameter, right? Commented Jun 19, 2012 at 3:28
  • damnit thanks dirk, thats what I get for copying from my shell history :s Commented Jun 19, 2012 at 3:47

4 Answers 4

1
#!/usr/bin/perl;
my $z= `du -h -d 1 /home/*`;
my @array  = split("\n",$z);
foreach my $ar(@array) {
my @ar = split("\t",$ar);
$ar = \@ar;
}

foreach my $entry(@array) {
print $entry->[0];
print $entry->[1];

}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the very useful suggestion! I am trying this out now
Hey user, I tried out this code, and unfortunately I got a list that repeats the following string for several lines: 20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/ho e20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/h me20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/ ome20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20M /home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home20MB/home
Actually, I was still using du -B MB /home. When I used your code verbaitm,it produced the following output: 4.0K/home/debug/Public4.0K/home/debug/.hplip4.0K/home/debug/Documents8.0K/home/debug/.ssh320K/home/debug/.kde208K/home/debug/.electricsheep4.0K/home/debug/Desktop4.0K/home/debug/Pictures4.0K/home/debug/Videos8.0K/home/debug/.mplayer24K/home/debug/.cache224K/home/debug/.thumbnails4.0K/home/debug/Templates12K/home/debug/.emacs.d12K/home/debug/.dbus8.0K/home/debug/.local188K/home/debug/.config4.0K/home/debug/Music4.0K/home/debug/Downloads19M/home/debug4.0K/home/ftp16K/home/lost+found
1

You can probably try and store them in a hash as follows:

#!/usr/bin/perl

use strict;
use warnings;

my $data = '1MB /home/work 4MB /user/bin';
my %values = split(' ', $data);
foreach my $k (keys %values) {
    print "$k: $values{$k}\n";
}
exit 0;

Note that ' ' as the first argument of split will match any whitespace character (so we make the most of it). The output for the above should be something like:

1MB: /home/work
4MB: /user/bin

You will have to work the original data into $data and check if a hash works for you.

2 Comments

Thanks for the very useful answer! I am trying this out now
dirk, unfortunately when I tried this out, I got a warning saying there was an "odd number of elements in hash assignment in line 7." I had to put an extra space in that list in order for it not to error out. Also, the keys I generated looked like the following: e: /, /: h, d: e, 2: M, B: , 1: M, b: u. I think i need to modify the split statement a bit more before I can get it to acknowledge the space in between the elements.
0

I'm sure you perl veterans won't like this solution much, but I basically resolved to my nix roots. I was having trouble with this earlier in a for loop, but I realized I can utilize pipes to be evaluated via the shell, so long as the answer is stored in a string.

my $z1; my $z2;

$z1 = `du -B MB /home | cut -f1`
$z2 = `du -B MB /home | cut -f2`

my @a1; my @a2;

@a1 = split("\n", $z1);
@a2 = split("\n", $z2);

Array @a1 holds values from first string, @a2 holds values from 2nd string.

My question to you guys is, is there a perl equivelent to the unix 'cut' utility? I.e. where I can split a strings output to the first tab-delimited field? This is a problem I'll have to explore.

Diego

Comments

0

I'm honestly not sure what you're trying to accomplish. If you simply want to have an array with n elements, each of which is a string with two columns in it, you need look no farther than

my @z1 = `du -B MB /home | tail -4`;

For example, the third line of your file could be accessed (remember perl arrays are 0-based):

print $z1[2];

producing output

20MB    /home/debug

More useful would be to capture each directory's size in a hash:

my %dir2size;
foreach (@z1) {
    my @line = split /\s+/;
    $dir2size{$line[1]} = $line[0];
}
foreach my $key (sort keys %dir2size) {
    print "$key: $dir2size{$key}\n";
}

which produces the output

/home/: 20MB
/home/debug: 20MB
/home/debug/Downloads: 1MB
/home/debug/Music: 1MB

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.