450 likes | 601 Views
Directory Operations. Moving around the Tree. Program has a working directory Use chdir to change working directory: chdir “/etc” or die “can’t chdir to /etc: $!”; Check return values. Working directory inherited from parent process. Using chdir without a parameter changes to home dir.
E N D
Moving around the Tree • Program has a working directory • Use chdir to change working directory: chdir “/etc” or die “can’t chdir to /etc: $!”; • Check return values. • Working directory inherited from parent process. • Using chdir without a parameter changes to home dir.
Globbing • The process of expanding wildcards on the command line: $ echo *.pm barney.pm dino.pm fred.pm wilma.pm
Glob Continued… $ cat >show_args foreach $arg (@ARGV) { print “Found arg: $arg\n” ; } ^D perl show-args *.pm Found arg: barney.pm Found arg: dino.pm …
Globbing within Perl my @all_files = glob “*”; my @pm_files = glob “*.pm”; my @really_all_files = glob “.* *”;
Alternative Syntax for Globbing • Originally glob had no name • You will often see a different syntax in older code: • Old: my @all_files = <*>; • New: my @all_files = glob “*”;
Glob, Alternative Syntax cont • Interpolation occurs before the glob: my $dir = “/etc”; my @dir_files = <$dir/* $dir/.*>; • The alternative glob syntax looks like the file read syntax - if there is a perl identifier between the angle brackets, then it’s a file read:
Glob, Alternative Syntax my @files = <FRED/*>; #glob my @lines = <FRED>; #File read my $name = “FRED”; my @files = <$name/*>;
Glob, Alternative Syntax • One exception: If the contents are a simple scalar var, then it’s an indirect file handle read: my $name = “FRED”; my @lines = <$name>; #File read • You can also explicitly specify a file handle read:
Glob, Alternative Syntax • You can also explicitly specify a file handle read: my $name = “FRED”; my @lines = readline FRED; my @lines = readline $name;
Directory Handles • An alternative way to get information from a file handle • A lower level operation - more work • Looks and acts like a file handle • Open with opendir • Read with readdir • Close with closedir
Directory Handles Cont… • Directory handles read filenames (and other info) from a directory: my $path = “/etc”; opendir DH, $path or die “Error $path: $!”; foreach $file (readdir DH) { print “Found file $file in $path\n”; } closedir DH;
Directory Handles Cont… • Directory handles are automatically closed at the end of a program • Automatically closed if the handle is reopened. • Names are returned in no particular order
Directory Handles Cont.. • List will include all files, not just those matching a particular pattern: while ($name = readdir DIR) { next unless $name =~/\.pm$/; … }
Directory Handles Cont.. • Filenames returned have no pathname, as opposed to Globs which return the full path. opendir MYDIR, $dirname or die ”$dirname: $!"; while (my $name = readdir MYDIR) { next if $name = /^\./; $name = "$dirname/$name"; next unless -f $name and -r $name; … }
Manipulating Files and Directories • Be careful when using the commands in this chapter!
Removing Files with Unlink • To remove a file from unix command line: $ rm slate bedrock lava • In perl, use the unlink op: unlink "slate", "bedrock", "lava"; • We can combine unlink with glob: unlink glob "*.o";# rm *.o
Unlink cont.. • Return value for unlink tells you how many files were deleted: my $del = unlink "slate", "rock", "lava”; print "I deleted $del files(s) just now \n";
Unlink cont… • Use the return value to check if the delete was successful: foreach my $file (qw(slate rock lava)) { unlink $file or warn “can’t del $file $! \n"; }
Renaming Files • As simple as using the rename function: rename "old", "new"; • Similar to unix mv command: rename ”newpass”, ”/etc/passwd” • Returns false and sets $! if it fails.
Batch Renaming of Files foreach my $file (glob "*.old") { (my $newfile = $file) =~ s/\.old$/.new/; if (-e $newfile) { warn "can't rename, $newfile exists\n"; } elseif (rename $file, $newfile) { #success } else { warn "rename of $file failed: $!\n"; } }
Links and Files • A mounted volume is a disk drive • It contains any number of files and dirs • Each file is stored in an inode. • Directories are special files with lists of filenames and inodes. • There are two special entries in a directory: . “dot” - Refers to the current dir .. “dot-dot” - Parent directory
Inodes • All inodes have a link count - it is incremented every time a filename is linked to it. • You can tell if an inode is free by checking for a link count of 0 • Directories will have a link count of at least 2
Inodes and Link Counts • An ordinary file inode will have an inode count of more than one if there are hard links to the file: $ ln chicken egg • If successful, both names are valid for the file. Neither name is “more real” • If “chicken” is deleted, file still exists as “egg”.
Link Counts cont.. • Directory listings (almost) always refer to inodes on the same mounted volume. • Hard links cannot span file systems • Can’t hard link to a directory, only files. • Linking across directories or file systems can be achieved with a symbolic link.
Symbolic Links • A directory entry that tells the system to look elsewhere for the file. $ ln -s chicken egg • Egg is not the “real” name - link count is not increased. • Symbolic links can point to any file or dir, including ones that don’t exist.
Symbolic Links in Perl symlink “chicken”, “egg” or warn “Can’t symlink $!”; • Symbolic links don’t preserve data, if we delete the file chicken, the data is gone. • In this case, test -l “egg” would report true, test -e “egg” would report false.
Readlink Operator • Use readlink to see where a symbolic link points: my $perl = readlink “/usr/bin/perl”; • If the argument is not a symbolic link, readlink returns undef. • Both symbolic and hard links can be removed with unlink.
Making Directories • To create a directory inside the working dir: mkdir “fred”, 0755 or warn “Can’t mkdir $!” • mkdir returns true on success and $! is set on failure. • The second (optional) parameter is the initial permission setting for the directory. Usually it’s given in octal
Making Directories cont.. • Be careful when defining permissions, a string will not be converted to octal: my $name = “fred”; my $permissions “0755”; mkdir $name, $permissions; • The above example would create the directory with permissions 01363.
Directory Permissions with oct • To force a var to be octal: mkdir $name, oct($permissions); • oct function is useful when we're getting permissions from the user: my ($name, $perm) = @ARGV; mkdir $name, $oct($perm) or die "cannot create $name: $!";
Removing Empty Directories • To remove empty directories, use rmdir function: rmdir glob "fred/*”; foreach my $dir (qw(fred barney betty)){ rmdir $dir or warn ”error $dir: $!\n"; }
Removing Empty Dirs cont.. • Just link unlink, rmdir returns the number of dirs removed. • If called with a single directory name, it will return an error in $! if necessary • rmdir will fail on a non empty directory, to delete, you must first empty the directory contents:
Removing Empty Dirs cont.. my $temp_dir = "/tmp/scratch_$$"; mkdir $temp_dir, 0700 or die “can’t make $temp_dir: $!"; ...#use $temp_dir for temporary files... unlink glob "$temp_dir/* $temp_dir/.*"; rmdir $temp_dir;
Modifying Permissions • To change a file’s permissions use chmod: chmod 0755, "fred", "barney"; • Returns number of successfully altered files. Sets $! on error if called with single arg • First parameter is the unix permission value. • symbolic permissions that are allowed in the shell’s version of chmod (eg: g+x) are not available in the basic perl chmod function
Changing Ownership • If the OS permits, can change ownership and group membership using the chown function. Must be numeric uids and gids: my $user = 1004; my $group = 100; chown $user, $group, glob "*.o";
Changing Ownership cont.. • Get numerical ids with getpwnam and getgrnam: defined (my $user = getpwnam ”ali") or die "bad user"; defined (my $group = getgrnam "users") or die "bad group"; chown $user, $group, glob "/home/ali/*";
Changing Timestamps • use utime to set timestamps • First two args give new access time and modification times, and remaining args are list of filenames • Times are in internal timestamp format: my $now = time; my $ago = $now - 24 * 60 * 60 utime $now, $ago, glob "*” • ctime will be set to current time.
Using Simple Modules • Consider splitting basename from dirname: my $name = "/usr/local/bin/perl"; (my $basename = $name) =~ s#.*/##; • This code makes assumptions about what system we’re on. It’s also been done before! • Perl has modules which are extensions to its functionality.
File::Basename Module • Routines involving file basenames • Declare it at the top of your perl: use File::Basename; • Use instructs perl to load the module. my $name = "/usr/local/bin/perl"; my $basename = basename $name; • This will now work independent of OS. • Other functions provided by this module include dirname
Importing parts of Modules • What if you want to use File::Basename, but you have a subroutine called &dirname. • In this case, tell perl what to import: use File::Basename qw/ basename /; • or perhaps import nothing? use File::Basename qw/ /; • Without an import list, we must use the function’s full name: $dirname = File::Basename::dirname
File::Spec Module • What’s wrong with this code? use File::Basename; print "Please enter a filename: "; chomp(my $old_name = <STDIN>); my $dirname = dirname $oldname; my $basename = basename $old_name; $basename =~ s/^/not/; my $new_name = "$dirname/$basename"; rename ($old_name, $new_name) or warn “$!”;
File::Spec Module Cont… • Use the File::Spec module for manipulating names of files, directories and other things. • File::Spec is an OO module. Because of this, you'll alwasy cal File::Spec methods with their full names:
File::Spec Module cont.. use File::Spec; my $name = File::Spec->catfile($dir, $base); rename ($filename, $name) or warn "Can't rename '$old_name' to '$new_name': $!";