Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I am trying to write a script to do the following:

1. Open Directory /var/log/cr_user
2. Pick Up One Of The Randomly Named Files In This Folder And Open It
3. Data In That File Is Seperated With A ',' So Split The Data Into Variables That I Can Use.
4. Close The File And Delete It
5. Move On To The Next File In The Directory
6. Once All Files In Directory Are Deleted, Gracefully Exit

Here is an example of one of the files:
Joe Bloggs,joe,Burton,joe@hotmail.com,google,80.10.10.123
And here is the code i have so far, that doesn't seem to work:
#! /usr/bin/perl -T use warnings; use strict; @file = `ls /var/log/cr_user`; foreach $file { open(FILE, "/var/log/cr_user/$file") || die; @account=<FILE>; close(FILE); foreach $account { ($fullname, $username, $mothers, $email, $referral, $ip) = split(/ +,/, $account); print "$fullname $username $mothers $email $referral $ip"; } unlink $file; }
I am sure there must be a better way of doing this, as this code looks very 'flakey' (and doesnt work), also i doubt it will exit gracefuly once all files are processed.

Thanks in advance

Replies are listed 'Best First'.
Re: Opening Unknown Filenames
by Aighearach (Initiate) on Jul 05, 2003 at 09:58 UTC
    Okay, lets start at the start.
    1. Open Directory /var/log/cr_user
    Good idea, but your code doesn't follow it. Instead of opening and reading the directory, you run ls and read it's output. I recommend something like:
    my $dir = '/var/log/cr_user'; opendir( my $dh, $dir ) or die "failed opening directory $dir: $!"; my @files = grep { ! /^\./ } readdir( $dh ); # skips dirs . and .. and + all dotfiles # faster but less readable would be something like grep { substr( $_, +0, 1 ) ne '.' ) }
    Next, your foreach doesn't specify it's list. It should read
    foreach my $file ( @files ) {
    Same for
    foreach my $account ( @account ) {
    I added the my declarations in there, too, you're need to declare all your vars that way for strict mode to work.
    --
    Snazzy tagline here

      5.6.0+ glob() uses readdir internally already. Use that and save on the readability: glob "/var/log/cr_user/*".

        I hardly think using "glob" is more readable, though <$dir/*> might be.

        I'm not really sure it is though. It's more compact, to be certain. Assuming what I did in removing the dotfiles is an invariably desired behavior, the glob works fine. But I'd rather use an explict readdir on account of, what if I decide I want the dotfiles after all? If I'm using a readdir I only have to change the grep to grep { ! /^\.\.?$/ } or  grep { /[^\.]/ } whereas if you're using glob, you have to change the whole thing to use the readdir anyways. And so if you always start with glob, as soon as you need a dotfile you'll find yourself with a mixed bag using both. Hardly more readable, that.

        If the tools isn't a sysadmin tool, it might be fine to assume you're not wanting to include dotfiles.
        --
        Snazzy tagline here

      I just tried to do it your way, but had no success. Instead i tried writing it like below, but now i am stuck with the fact that i get the error 'No such file or directory' and the code doesn't run with taint!
      #! /usr/bin/perl my $directory = '/var/log/cr_user/'; opendir DIR, $directory or die $!.$/; my @files = readdir(DIR); closedir DIR or warn $!.$/; for my $file (@files) { open FILE, $file or die $!.$/; my ( $username, $domain, $email, $service ) = split /,/, <FILE>; print "$username"; close FILE or warn $!.$/; unlink $file; }

        The filenames returned from readdir are relative. You can either chdir to the directory or add the file path:

        chdir '/var/log/cr_user/'; # or use File::Spec; my $dir = '/var/log/cr_user/'; my @files = map { File::Spec->catfile( $dir, $_ ) } grep { $_ !~ /^\.{1,2}/ } readdir DIR;
Re: Opening Unknown Filenames
by demerphq (Chancellor) on Jul 05, 2003 at 14:15 UTC

    Your algorithm (as written, it doesnt correspond to your code in my mind) is an accident waiting to happen. Luckily your implementation while having issues already covered doesnt have the problem. It should IMO look like this:

    1. Get list of all files in '/var/log/cr_user' 2. Foreach file in list 3. read file contents and process each line of CSV text 4. close and then delete the file 5. Exit

    something like this maybe?

    use strict; use warnings; my $path='/var/log/cr_user'; # =shift @ARGV; # is better IMO # clear @ARGV of junk so we can use <> for file IO @ARGV=(); #get the files my @files=glob "$path/*"; # as long as there are still files while (@files) { #remove the first file from list and store it my $to_delete=shift @files; # stick the file in @ARGV so <> can do its ting. push @ARGV,$to_delete; # iterate over the lines in the file while (<>) { # lose newline chomp; # split the line by ',' my @vars=split/,/; # print the results print join(" ",@vars),"\n"; } # delete the file unlink $delete; } #and fall of the end of the script "gracefully exit :-)"

    This is untested, but potential typos aside it should do the trick.

    HTH


    ---
    demerphq

    <Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
Re: Opening Unknown Filenames
by Limbic~Region (Chancellor) on Jul 05, 2003 at 12:21 UTC
    hiddenlinux,
    I still don't have a clear picture of what the end result is, so I am going to offer my advice based off the requirements you indicated earlier. Of course you might have to debug it a little, I have been away from Perl for about a month.
    #!/usr/bin/perl -Tw use strict; my @data; my @Files = grep { ! -d } </var/log/cr_user/*>; while (my $file = shift @Files) { unless (open (FILE,"$file")) { # Tell yourself instead of deleting it next; { while (<FILE>) { my @fields = split /,/; push @data , \@fields; } unlink $file; } foreach my $a_ref (@data) { print "Full Name = $a_ref->[0]\n"; print "User Name = $a_ref->[1]\n"; print "Mothers = $a_ref->[2]\n"; print "Email = $a_ref->[3]\n"; print "Referral = $a_ref->[4]\n"; print "IP = $a_ref->[5]\n"; }

    You could use a different data structe if you wanted. Additionally, if the data really is comma delimited then you should consider one of the CSV modules on CPAN since an imbedded comma will cause the code will not work properly.

    Cheers - L~R

Re: Opening Unknown Filenames
by Anonymous Monk on Jul 05, 2003 at 09:32 UTC
    • The description is so idiotically purposeless that it could only be homework.
    • Your script can't even compile, so "exit gracefully" is your last worry.

    Perhaps you should RTFM a bit more before coming here, don't you think so?

      Actually, processing a directory full of files is pretty close to perl's reason for existing at all. The last two programs I wrote at work do exactly that. OMG! I must be doing homework, at work! For work! Or maybe you should go away and sulk in your parent's basement for a bit longer. Perhaps you should experience the real world before coming here, don't you think so?

      ____________________
      Jeremy
      I didn't believe in evil until I dated it.

    A reply falls below the community's threshold of quality. You may see it by logging in.