This is an advance chapter of Learning Perl 6 by Randal L. Schwartz and brian d foy. It is incomplete and may contain merely notes or an outline for future work. It may also contain sections of their writing from other sources, although these are noted where possible.
This work is copyrighted under a contract between O'Reilly Media and the authors, and you cannot repost it or distribute it without permission.
list the Perl 6 items on which this chapter depends. This will help determine the order of chapters and the topics to discuss.
At most command lines, whether that's unix, DOS, or something else, we can write a pattern to stand in for a list of files whose
name match that pattern. This is called globbing[1]. We can use this with the unix ls command (dir on DOS> to list all of the files with the .p6 extension:
$ ls *.p6
XXX: file list
It's the shell that does that expansion, not the ls command, so we can do the same thing for
our Perl 6 program:
$ ./show_files.p6 *.p6
XXX
In our program, we get the command line arguments in the global array @*ARGS, so we can go through that list and print each filename that matched:
XXX: program to print the filenames.
We don't need the command line though, because we can do this inside our program using either a glob or a directory handle.
XXX: note about hidden files.
XXX: note about . and ..
The glob operator does the same thing that the shell does, but from within our program. It uses
the same pattern as the shell.
my @files = glob( '*' );
If we want to get the hidden files too, we
my @all_files = glob( '.* *' );
To get just the hidden files, we
my @hidden = glob( '.*' );
So far all of those get the files in the current working directory. The glob pattern can handle sub-directories too (as long as we have the right syntax for my particular operating system):
my @jane_files = glob( "jane/*" );
When we look at those files, we see that they have their sub-directory name attached to them:
We can even merge the list of files from more than one sub-directory:
my @merged_files = glob( "george/* jane/*" );
In the object-oriented syntax,
$string.glob
We can open a directory handle to get filenames one at a time. The glob syntax gave us
back a (potentially big) list of filenames all at once, but sometimes we only want to get the next filename. We'll do our
processing and get another filename when we're done. That way, we don't waste a lot of memory storing the entire list of filenames.
This is similar to reading standard input one line at a time instead of all at once.
To get a directory handle, I use the opendir method on the scalar that holds the directory
name.
my $directory = 'Rosie';
my $dirhandle = $directory.opendir err die "Could not open $directory: $!";
for =$dirhandle -> $file {
say "I found $file in $directory";
}
$dirhandle.close;
#!/usr/local/bin/pugs
my $start_dir = @*ARGS[0] // '/Users/brian/Desktop';
list_dir( $start_dir, 0 );
sub list_dir ( Str $directory, Int $level ) {
#XXX my $dh = $directory.opendir err return;
my $dh = try{ $directory.opendir } || return;
for $dh.readdir -> $file {
next if $file ~~ /^\.\.?$/;
say( "\t" x $level ~ $file );
next unless "$directory/$file" ~~ :d;
list_dir( "$directory/$file", $level + 1 );
}
}
With a reference:
#!/usr/local/bin/pugs
my @dirs = [ @*ARGS[0] // '/Users/brian/llama6/Scripts', 0 ];
while( my $pair = @dirs.shift )
{
my( $directory, $level ) = @($pair);
say "Directory $directory, level $level";
my $dh = try{ $directory.opendir } || next;
for $dh.readdir -> $file {
next if $file ~~ /^\.\.?$/; next if $file ~~ '.svn';
say( "\t" x $level ~ $file );
@dirs.unshift( [ "$directory/$file", $level + 1 ] ) if "$directory/$file" ~~ :d;
}
}
Without the reference:
#!/usr/local/bin/pugs
my @dirs = @*ARGS[0] // '/Users/brian/llama6/Scripts', 0;
while( my $directory = @dirs.shift )
{
my $level = @dirs.shift;
say "Directory $directory, level $level";
my $dh = try{ $directory.opendir } || next;
for $dh.readdir -> $file {
next if $file ~~ /^\.\.?$/; next if $file ~~ '.svn';
say( "\t" x $level ~ $file );
@dirs.unshift( "$directory/$file", $level + 1 ) if "$directory/$file" ~~ :d;
}
}
* chdir
* no more <> syntax
List resources for the topic, especially since things will change
See Section XX in Appendix A for the answers to these exercises: