Panasonictoilet has asked for the wisdom of the Perl Monks concerning the following question:
Hello fellow monks,
I am trying to write a script that goes through home directories and does a du but excludes stuff in specific Maildir directories, cur, new, tmp and courierimapkeywords. I have tested it on the commandline and I have it in my perl script as below:
$du=`du -ch $homedir | grep -v '^.*Maildir.*cur$' | grep -v '^.*Maildir.*tmp$' | grep -v '^.*Maildir.*new$' | grep -v '^.*Maildir.*courierimapkeywords$'`;
print $du;
However this does not work and is giving me the following errors:
du: cannot access `~skim': No such file or directory
sh: .*Maildir.*tmp: not found
sh: .*Maildir.*courierimapkeywords: not found
I have used backticks before for simple operations but is this too complicated for backticks, or do i need to escape certain character out, if so how??
Please help enlighten me fellow monks!
Re: du with backticks
by snoopy (Curate) on Mar 20, 2008 at 01:18 UTC
|
#/usr/bin/perl
use warnings; use strict;
use Filesys::DiskUsage qw/du/;
use File::Find::Rule;
use YAML;
my $rule = File::Find::Rule->new;
$rule->directory();
$rule->not($rule->new->name( qr/^.*Maildir.*(cur|new|courierimapkeywor
+ds)$/));
my @dirs = $rule->in('.');
warn "dirs=@dirs";
my %sizes = du( {
'make-hash' => 1,
'human-readble' => 1,
} , @dirs);
print YAML::Dump(\%sizes);
| [reply] [d/l] |
Re: du with backticks
by JStrom (Pilgrim) on Mar 20, 2008 at 01:15 UTC
|
You're interpolating $' into your string in quite a few places. I doubt that's what you wanted. Try escaping those $ s in the grep commands.
You might find it easier to dispense with the pipline all together. readpipe (i.e. the backticks) returns a list of the lines read when in list context so you could write:
print grep $_ !~ /^.*Maildir.*cur$/, grep ..., readpipe "du -ch $homedir";
| [reply] [d/l] |
Re: du with backticks
by pc88mxer (Vicar) on Mar 20, 2008 at 05:09 UTC
|
This is not your problem, but it might be of interest to know that ~-expansion is actually done by the shell. So, even though the following calls look like they do the same thing, the first two work as expected, but the last one doesn't:
`du ~user`;
system("du ~user");
system("du", "~user"); # doesn't work
Generally you are better off calling getpwnam() to get a user's home directory instead of using ~user.
my $user = ...;
my $home = (getpwnam($user))[7];
system("du", $home); # etc.
| [reply] [d/l] [select] |
Re: du with backticks
by blahblahblah (Priest) on Mar 20, 2008 at 01:35 UTC
|
The first error message, du: cannot access `~skim': No such file or directory, made me curious. I think that if you reduce your program to a very simple command you'll find that it's not running from the right directory or that ~skim doesn't exist?
my $homedir = '~bogus';
$du=`du -ch $homedir`;
print "$du";
produces a similar message for me:
./test
du: cannot access `~bogus': No such file or directory
0 total
| [reply] [d/l] [select] |
Re: du with backticks
by graff (Chancellor) on Mar 20, 2008 at 08:22 UTC
|
IMO, when you need to "grep" stuff, you're better off doing it in perl. I'm agnostic about shell "du" vs. perl-module solutions for the same thing, but stringing a bunch of separate "grep" commands in a pipe like the OP does is just ugly and so unnecessary. I'd be content with something like this (not tested):
$du = join( '',
grep !/^.*?Maildir.*?(?:cur|tmp|new|courierimapkeywords)$/
+,
`du -ch $homedir` );
print $du;
Anything you can do to shorten/constrain/simplify the stuff in backticks is generally a good idea, esp. in terms of eliminating "shell-magic" characters as much as (or completely if) possible. | [reply] [d/l] |
|