Forcing list context

B

Brian Greenfield

I was writing a script that needed to find the free space on a mounted
Linux partition (mounted on /backup) and I wrote the following
snippet:

my @res = split /\s+/, grep m{/backup}, `df`; # 1

The problem being that the second argument of split is evaluated in
scalar context so grep returns the number of matches instead of the
actual match (there will only ever be a single match). I got round
this problem by inserting a join so that grep is evaluated in list
context:

my @res = split /\s+/, join '', (grep m{/backup}, `df`); # 2

While this works, it seems a little kludgey. I know I could have
indexed grep's list result:

my @res = split /\s+/, (grep m{/backup}, `df`)[0]; # 3

I intended to go on to do a list splice to get the fields I wanted
(the second to fourth) and I wanted to avoid the using indexing twice:

my @res = (split /\s+/, (grep m{/backup}, `df`)[0])[1..3]; # 4

I ended up using the splice with method 2:

my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

Does Perl offer any other ways of forcing list context?

Sample output from df, for reference

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hdb2 29300456 20002976 7809060 72% /backups
/dev/hdc1 12998064 3069480 9268316 25% /mirrors
 
J

James Willmore

I was writing a script that needed to find the free space on a
mounted Linux partition
Does Perl offer any other ways of forcing list context?

Sample output from df, for reference

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hdb2 29300456 20002976 7809060 72% /backups
/dev/hdc1 12998064 3069480 9268316 25% /mirrors

A simple one liner that gets what you want is ...

host> df | perl -ne 'if(/home/){@line = split;print $line[3],"\n";}'

My though is it's easier to use a regex to get what you want versus
using 'grep' in the context of what you're trying to do. However,
that's my opinion :)

However, you may want to look over the Filesys::DiskFree module. It
may make your tasks easier :)


--
Jim

Copyright notice: all code written by the author in this post is
released under the GPL. http://www.gnu.org/licenses/gpl.txt
for more information.

a fortune quote ...
A little inaccuracy sometimes saves tons of explanation. -- H.
H. Munroe
 
L

l v

James said:
I was writing a script that needed to find the free space on a
mounted Linux partition

Does Perl offer any other ways of forcing list context?

Sample output from df, for reference

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hdb2 29300456 20002976 7809060 72% /backups
/dev/hdc1 12998064 3069480 9268316 25% /mirrors


A simple one liner that gets what you want is ...

host> df | perl -ne 'if(/home/){@line = split;print $line[3],"\n";}'

My though is it's easier to use a regex to get what you want versus
using 'grep' in the context of what you're trying to do. However,
that's my opinion :)

However, you may want to look over the Filesys::DiskFree module. It
may make your tasks easier :)

using the perl option -a will auto-split $_ into @F, therefore

df | perl -nae 'print "$F[3]\n" if(/home/)'

Len
 
L

l v

Brian said:
I was writing a script that needed to find the free space on a mounted
Linux partition (mounted on /backup) and I wrote the following
snippet:

my @res = split /\s+/, grep m{/backup}, `df`; # 1

The problem being that the second argument of split is evaluated in
scalar context so grep returns the number of matches instead of the
actual match (there will only ever be a single match). I got round
this problem by inserting a join so that grep is evaluated in list
context:

my @res = split /\s+/, join '', (grep m{/backup}, `df`); # 2

While this works, it seems a little kludgey. I know I could have
indexed grep's list result:

my @res = split /\s+/, (grep m{/backup}, `df`)[0]; # 3

I intended to go on to do a list splice to get the fields I wanted
(the second to fourth) and I wanted to avoid the using indexing twice:

my @res = (split /\s+/, (grep m{/backup}, `df`)[0])[1..3]; # 4

I ended up using the splice with method 2:

my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

Does Perl offer any other ways of forcing list context?

Sample output from df, for reference

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hdb2 29300456 20002976 7809060 72% /backups
/dev/hdc1 12998064 3069480 9268316 25% /mirrors

I think you are attempting to do too much in one line. However @{[ ]}
can be used to force list context. Split is looking for a scalar and
you are feeding it an array of 1. Try the following:

#!/usr/bin/perl

my @result = grep m{/backups}, `df`;
mmy @res = split (/\s+/, $result[0]);

for my $r (@res) {
print "r = $r\n";
}


I would personally add the file system to the df command to lighten
greps load, if you have alot of mount points. df /backups will return
for /backups only, including the header.
my @result = grep m{/backups}, `df /backups`;

my $.02
Len
 
B

Bruce Horrocks

Brian said:
I ended up using the splice with method 2:

my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

Does Perl offer any other ways of forcing list context?

Absolutely not the answer to the question that you asked, but a neat-ish
(untested) solution is:

my $res = `df | awk '/backups/ {print $4}'`

Regards,
 
L

Lawrence D'Oliveiro

Brian Greenfield said:
I was writing a script that needed to find the free space on a mounted
Linux partition (mounted on /backup)...

Just a thought, but on Linux, rather than forking df, you can read all
information on current mount points from /proc/self/mounts. This returns
one line per mount point, containing the following space-separated items:

device mountpoint filesystem flags fsck1 fsck2
 
J

John W. Krahn

Brian said:
I was writing a script that needed to find the free space on a mounted
Linux partition (mounted on /backup) and I wrote the following
snippet:

my @res = split /\s+/, grep m{/backup}, `df`; # 1

The problem being that the second argument of split is evaluated in
scalar context so grep returns the number of matches instead of the
actual match (there will only ever be a single match). I got round
this problem by inserting a join so that grep is evaluated in list
context:

my @res = split /\s+/, join '', (grep m{/backup}, `df`); # 2

While this works, it seems a little kludgey. I know I could have
indexed grep's list result:

my @res = split /\s+/, (grep m{/backup}, `df`)[0]; # 3

I intended to go on to do a list splice to get the fields I wanted
(the second to fourth) and I wanted to avoid the using indexing twice:

my @res = (split /\s+/, (grep m{/backup}, `df`)[0])[1..3]; # 4

I ended up using the splice with method 2:

my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

Does Perl offer any other ways of forcing list context?

Sample output from df, for reference

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hdb2 29300456 20002976 7809060 72% /backups
/dev/hdc1 12998064 3069480 9268316 25% /mirrors

I would do it this way:

my @res = `df /backup` =~ /(?<=\s)\d+(?=\s)/g;



John
 
B

Brian Greenfield

Brian said:
my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

I think you are attempting to do too much in one line.

I know. It just sorta grew:)
However @{[ ]}
can be used to force list context.

Which is what I was looking for, thanks. (Even though I wan't be using
it - I much prefer John W. Krahn method's oven my own.)
 
B

Brian Greenfield

Brian said:
my @res = (split /\s+/,
join '', (grep m{/backup}, `df`))[1..3]; # 5

I would do it this way:

my @res = `df /backup` =~ /(?<=\s)\d+(?=\s)/g;

That's much cleaner than my overly-complicated method. Thanks John.
(And thanks for pointing out 'df /backups' - I never thought to look
first at arguments to df.
 
M

Martien Verbruggen

I was writing a script that needed to find the free space on a mounted
Linux partition (mounted on /backup) and I wrote the following
snippet:

[snip]

Apart from all the other suggestions you've had about parsing df output
(and mind that it can get quite complicated to do that reliably), and to
read the /proc file system directly, there is the Filesys::Df module,
available from CPAN, which is a wrapper wround Filesys::Statvfs, which
is a wrapper around your system's statvfs call.

Using that will probably make your program more portable (to all
environments where statvfs is available, which includes linux, and all
major unices I know of), give you more information when needed, and most
likely is a lot faster and lighter on the machine as well.

Apart from that, there are also Filesys::DiskFree (runs external df
command), and Filesys::DiskSpace (calls statvfs), neither of which I've
tried.

Martien
 
M

Michele Dondi

A simple one liner that gets what you want is ...

host> df | perl -ne 'if(/home/){@line = split;print $line[3],"\n";}'

df | perl -lne '/home/ and print +(split)[3]'

or

df | perl -lne 'print +(split)[3] if /home/'

[Just to pinpoint that it is not necessary to create an intermediate
variable...]


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top