So I have been playing around with perl the last week and trying to get a handle on it. Im hardly able to write anything decent without having perlmonks or perldoc open though, but I am learning!
Wanted to know what/how I could improve the following code or in what ways you would have done it differently. I really like seeing more than one approach, and I need help pointing out my pitfalls.
Its very simple code, just traverses a specified directory and changes the permissions for files and/or directories. It is my perl way of doing the following with GNU Find.
find [base directory] -type [f|d] -exec chmod [perm] {} \;
Here it is, input greatly appreciated. Im still a newbie though.
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
use File::Find;
my %opts = (
verbose => '',
directory => './',
filemode => '',
dirmode => ''
);
if(!GetOptions('verbose' => \$opts{'verbose'},
'filemode:s' => \$opts{'filemode'},
'dirmode:s' => \$opts{'dirmode'})) {
usagedie();
}
#make sure each argument passed is either a file or directory
foreach (@ARGV) {
usagedie() if (!-f || !-d);
}
#we need to perform at least one option
usagedie() if (!$opts{'filemode'} && !$opts{'dirmode'});
#use default directory if argument not set on command line
find(\&fileop, $opts{'directory'}) unless @ARGV;
find(\&fileop, @ARGV) if @ARGV;
sub fileop {
#set the right permissions based on if a file or a directory
#only set permissions of the mode is set
chmod oct($opts{'filemode'}), $_ if -f && $opts{'filemode'};
chmod oct($opts{'dirmode'}), $_ if -d && $opts{'dirmode'};
print $File::Find::name . "\n" if $opts{'verbose'} && (-f || -d);
}
sub usagedie {
print "Usage: setperm.pl [-v] [-f perm] [-d perm] [Directory]\n";
print "-v, --verbose\t show files changed by script\n";
print "-f, --filemode\t octal mode to change files to\n";
print "-d, --dirmode\t octal mode to change directories to\n";
exit(0);
}
Updated Code:
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
use File::Find;
my %opts = (
verbose => '',
filemode => '',
dirmode => ''
);
if (!GetOptions(\%opts, 'verbose', 'filemode:s', 'dirmode:s')) {
usagedie();
}
#make sure each argument passed is either a file or directory
foreach (@ARGV) {
usagedie() if (!-f && !-d);
}
#we need to perform at least one option
usagedie() if (!$opts{'filemode'} && !$opts{'dirmode'});
#make sure correct octal values were used
$opts{'filemode'} = chkperm('File', $opts{'filemode'});
$opts{'dirmode'} = chkperm('Directory', $opts{'dirmode'});
#use default directory if argument not set on command line
find(\&fileop, @ARGV ? @ARGV : './');
sub fileop {
#set the right permissions based on if a file or a directory
#only set permissions if the mode is set
if (-f && $opts{'filemode'}) {
chmod $opts{'filemode'}, $_;
}
elsif (-d && $opts{'dirmode'}) {
chmod $opts{'dirmode'}, $_;
}
else {
#dont print if we didnt modify file perms
return;
}
print $File::Find::name . "\n" if $opts{'verbose'};
}
sub chkperm {
my ($type, $perm) = @_;
#zero length strings are defined values
#our $perm 's by default are set to ''
if ($perm) {
return ($perm =~ /^[0-7]{4}$/)
? oct($perm)
: die "Incorrect $type mode $perm\n";
}
return;
}
sub usagedie {
print "Usage: setperm.pl [-v] [-f perm] [-d perm] [Directory]\n";
print "-v, --verbose\t show files changed by script\n";
print "-f, --filemode\t octal mode to change files to\n";
print "-d, --dirmode\t octal mode to change directories to\n";
exit(1);
}
Thanks to all of ya'll who helped out. I tested it a few times and it worked perfect, I will test more, but I wanted to show what the combined efforts did to the script before it went off the front page.
I'll be adding an exclude option soon too. This will allow you to exclude directories or files. Thanks!
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.