On Wed, Aug 28, 2013 at 11:48:45AM -0400, Harry Putnam wrote:
> I know the format and scripting are probably pretty backwards but I
> seem to recall it being important to have a `return' line in a
> function. 
> 
> The code below was a script by itself but now I need to turn it into a
> function inside a larger script... I've done something that sort of
> works but fails on a specific file name that looks like `.#somefile'.
> 
> I'll show the code the way I've tried to turn it into a sub routine.
> So, I'd like comments both on how to write this more like a proper sub
> routine and any other why ideas.

You should have included a more complete program. Since you are
inexperienced with Perl it would be wise for us to be able to
point out all of your bad habits. :) Hopefully you are at least
using strict and warnings pragmas.

> What the sub is supposed to do is plow thru a couple of directories and
> reset the proper owner and group after some other operations have
> changed them.
> 
> Its called like this in a getops operation:
> 
> if($opt_o ) {
>   if (@ARGV) {
>     usage();
>     print "The \`-o' flag must be used by itself and\n",
>           " \`-o' flag requires user to be root .. exiting\n ";

You can use a heredoc string to write multiline text more easily:

    print <<EOF;
the \`-o' flag must be used by itself and
 \`-o' flag requires user to be root .. exiting.
EOF

You are also wrapping that text at only ~45 characters, which is
a bit early for probably any device you'll use. >:) It may be
wiser to wrap around 72 or 80, or not wrap at all and let the
terminal do it for you.

>     exit;

A better behaved program would signal error back to the caller so
they can react appropriately (e.g., if another program called
this program and relies on this program successfully changing the
ownership then it can also exit with an error instead of going
ahead and trying to do something that doesn't apply). Typically 0
signals success, and non-zero error. 1 or -1 are common, but it
can practically be anything in the range supported by your perl
and platform.

    exit 1;

>   }
>   chOwnGrp();
>   exit;

This exit isn't strictly necessary since the program will
automatically exit when the end is reached.

> }
> 
> sub chOwnGrp {
>   use File::Find;

A module cannot actually be loaded within a lexical scope, and
the use will be processed before any other code (despite being
inside of that subroutine) so you should move it to the top of
the program with other use directives so it's easier to spot.

To demonstrate:

#!/usr/bin/perl

use strict;
use warnings;

print join ', ', keys %File::Find::;

sub never_called {
    use File::Find;
}

__END__

The reason for this can be learned about in `perldoc -f use' and
`perldoc perlmod'.

>   my $buffer = '/merb';
>   my $module = '/usr/local/common/merc';
>   my $uname = $ENV{'LOGNAME'};
>   my $uid = '1000';
>   my $gid = '1050';

For a short program that isn't used often there's nothing
particularly wrong here (except for maybe relying on LOGNAME and
those constant uid and gid like that), but for a more robust
program you'd probably want to inject those parameters into the
subroutine through arguments. Or if they really will never
change, perhaps you might declare them using the constant pragma
instead (I am not familiar with those terms so I cannot criticize
the variable names or given them better context in the scope of
the program):

    use constant {
        BUFFER => '/merb',
        GID => 1050,
        MODULE => '/usr/local/common/merc',
        UID => 1000,
    };

>   if ($uname =~ /root/) {
>     print "Would you like to set owner:group on BUFFER and MODULE?\n",
>           "If so, we will run chown -R $uid:$gid $buffer and\n",
>           "chown -R $uid:$gid $module\n",
>           "[y/n] > ";

Again we could use a heredoc again. Unfortunately, constants are
not interpolated like variables are so that won't work. You can
either assign the constants to lexicals (kind of defeats the
purpose in this case) or use the "magic" [not really a single
operator] turtle-operator: @{[]}.

    print <<EOF;
Would you like to set owner:group on BUFFER and MODULE?
If so, we will run chown -R @{[UID()]}:@{[GID()]} @{[BUFFER()]} and
chown -R @{[UID()]}:@{[GID()]} @{[MODULE()]}
EOF
    print '[y/n] >';

>     my $answer = <STDIN>;
>     if ($answer =~ /^y$/) {
>       find(
>            sub {
>              chown $uid, $gid, $_ or warn "could not chown '$_': $!";
>            },
>            $buffer, $module
>           );
>     }
>   } else {
>     print "You must be root to run with this flag (-o)  effectively.. 
> exiting\n";
>     print "Not root - tripped at line: <" . __LINE__ . ">\n";

Again we can use a heredoc. Instead though, see my next point.

>     exit;

Rather than exit()ing from a subroutine, it is often better to
either return a value indicating failure (e.g., boolean or error
status) or die() instead. This lets the caller decide if they
want to give up or do something else. Not only can die() be
caught and handled with eval(), but it also appends line
information by default so you can leave that second bit off
entirely:

    die 'You must be root to run with this flag (-o) effectively.';

>   }
> }

As Rob indicated, give us a more specific error if you still need
help with your program (it's hard to speculate what is going
wrong). If you want more code review then post a more complete
program.

Regards,


-- 
Brandon McCaig <bamcc...@gmail.com> <bamcc...@castopulence.org>
Castopulence Software <https://www.castopulence.org/>
Blog <http://www.bamccaig.com/>
perl -E '$_=q{V zrna gur orfg jvgu jung V fnl. }.
q{Vg qbrfa'\''g nyjnlf fbhaq gung jnl.};
tr/A-Ma-mN-Zn-z/N-Zn-zA-Ma-m/;say'

Attachment: signature.asc
Description: Digital signature

Reply via email to