Re: Reading
by mr.nick (Chaplain) on Feb 05, 2001 at 20:47 UTC
|
Instead of spawning an "ls" process, why not use only Perl stuff?:
#!/usr/bin/perl
sub getlast5 {
my $dir=shift;
my @files;
opendir DIR,$dir || die "Couldn't open '$dir': $!";
for my $x (sort { (stat($b))[9] <=> (stat($a))[9] } readdir DIR) {
next if $x eq "." || $x eq "..";
push @files,$x;
last if $#files==4;
}
closedir DIR;
@files;
}
print join("\n",getlast5(".")),"\n";
(it's pretty simple code, but I'm trying different styles :)
| [reply] [d/l] |
|
You may want to move the readdir DIR step to a point just prior to the sort so that you can properly filter the directory there... perhaps using a glob or File::Find. This way we can explicitly include only the file types we want, rather than excluding the . and .. (what about .bash_history or such files?) inside the for loop.
| [reply] |
|
I presume that files beginning with a dot where still eligable for transfer as he didn't say anything about that. But if he's mirroring an FTP site, I suppose a
next if $x=~/^\./;
would be appropriate (and take care of the directory stuff).
You be right, ichimunki, by using the example of 'ls -ltr', it doesn't include dot files ;)
| [reply] [d/l] |
|
|
opendir DIR,$dir || die "Couldn't open '$dir': $!";
For the main point of your code, I think it's excellent
the way that you've used sort() on stat() .
But, I hope it's helpful to point out that the
opendir() statement is broken, as it was written at
the time of my response, because it tests $dir for Truth rather than
opendir() , and that's not what you want.
To use the perlop '||' with opendir() the parentheses
are not optional. Otherwise, use or which is
more reliable in statements such as open() and opendir() , because
the precedence of or is so low that it doesn't even require
those pesky parentheses.
(deleted my own bad -here)
But, as I said, this is a small tweak that shouldn't take away
from what seems to me otherwise to be a good idea.
mkmcconn
| [reply] [d/l] |
Re: Reading from ls -lrt
by chipmunk (Parson) on Feb 05, 2001 at 20:56 UTC
|
You don't need to use the -l (letter ell) option if you just want the filenames. You can use -1 (numeral one) to specify one file per line, but that's the default behavior of ls when output isn't going to a terminal anyway.
Additionally, if you want the most recent files, instead of using -r and getting the last five files, you should use the default sort order and get the first five files. Thus:
my @files = (`ls -1t`)[0..4];
chomp(@files);
However, it might be preferable to do all this in Perl, and avoid spawning a shell and relying on the behavior of ls.
opendir(DIR, '.') or die "Can't opendir '.': $!\n";
my @files = readdir(DIR);
closedir(DIR);
@files = map $_->[0],
sort { $b->[1] <=> $a->[1] }
map { /^\./ ? () : [ $_, (lstat $_)[9] ] }
@files;
@files = @files[0..4];
| [reply] [d/l] [select] |
(ichimunki) Re: Reading directories
by ichimunki (Priest) on Feb 05, 2001 at 20:47 UTC
|
opendir, readdir and stat should make all this a lot more portable and allow you to be more explicit with what you are doing.
update: Heh. And Mr. Nick has already written a great example of this! | [reply] |
Re: Reading
by ChOas (Curate) on Feb 05, 2001 at 20:40 UTC
|
Hmmmm....
Quick, and NOT the Perl way I prefer:
my @File=map {(split)[-1]} `ls -ltr|tail -5`;
GreetZ!,
p.s. TIMTOWTDI: This is not my prefered way, but it is one.. and simple
print "profeth still\n" if /bird|devil/; | [reply] [d/l] |
Re: Reading
by kschwab (Vicar) on Feb 05, 2001 at 21:01 UTC
|
Assuming:
- You want to skip "." files and directories
- You need the 5 "newest" files
- You want only "regular" files
opendir(DIR,$somedir) or die;
@files=reverse sort {(stat($a))[9] <=> (stat($b))[9]}
grep(!/^\./ && -f "$somedir/$_" ,readdir(DIR));
( $#files > 4 ) && { @files=@files[0..4] };
closedir(DIR);
| [reply] [d/l] |
Re: Reading ls -lrt
by baku (Scribe) on Feb 05, 2001 at 20:57 UTC
|
opendir LSLRT, "$dir" or die "I hate you, $dir: $!";
# rewinddir not needed
@dir = readdir(LSLRT);
closedir LSLRT; # why 'or die,' if we're all done anyways?
for my $dirent (@dir)
{
next unless ( -f "$dir/$dirent" );
$mtime{$dirent} = (stat "$dir/$dirent")[9];
}
my @last_five = (map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $mtime{$_} ] }
keys %mtime)[-5..-1];
This is evil because I sort the whole thing and then
throw away most of it.
For easy-to-maintain:
my @last_five = chomp (`ls -1 --sort=time`)[0..4];
Corrections: Don't need to reverse
in the ls -1 form, and don't need to rewinndir.
N.B. that I use -1 because CygWin's ls will send ANSI colour codes if I leave it off :-(
| [reply] [d/l] [select] |
The title was supposed to be...
by azatoth (Curate) on Feb 05, 2001 at 20:40 UTC
|
"Reading from ls-lrt" but it got chopped, and for some reason I can't update it. Sorry for the waste of a node here too.
<font color="#0000ff"<Azatoth a.k.a Captain Whiplash
Get YOUR PerlMonks Stagename here!
A HREF="/index.pl?node_id=55997&lastnode_id=1072">Want to speak like a Londoner? | [reply] |
Re: Reading
by azatoth (Curate) on Feb 06, 2001 at 15:21 UTC
|
Just to keep you dudes updated, in the end i went for
# snippet of my code using Net::FTP
@files = reverse (map {
(split (/\s+/))[8];
} `ls -lrt F*`);
foreach $filename (@files[0..4]) {
COPY_FILES;
}
sub COPY_FILES {
$ftp = Net::FTP->new("$remserv") || die "Could not connect : $!\n";
$ftp->login("$user","$pass");
$ftp->cwd("$dir");
$ftp->put("$filename");
$ftp->quit;
}
I wrote it myself, and now I know a bit more about the mega-useful map !
| [reply] [d/l] [select] |