Shell.pm is great syntactic sugar. That is, until you need to invoke a command whose name contains characters permissible in shell identifiers but not in Perl identifiers. Examples: repo-add, python2.4, c++, etc...

IMHO, having to do "$cmd"->(@args) is clumsy and defeats the point of using Shell.pm.

In stead, I suggest that when using Shell.pm with explicit imports that would have this problem, the names should be perlified (tr/.-/_/ should do the trick).

Example:
use Shell 'repo-add'; ... repo_add(@args);

Here's my proposed patch:
--- Shell.pm.old 2008-07-08 12:09:00.000000000 -0700 +++ Shell.pm 2008-07-08 14:17:11.000000000 -0700 @@ -21,8 +21,9 @@ @EXPORT = 'AUTOLOAD'; } foreach my $sym (@EXPORT) { + (my $perlsym = $sym) =~ s/[^a-zA-Z0-9_]/_/g; no strict 'refs'; - *{"${callpack}::$sym"} = \&{"Shell::$sym"}; + *{"${callpack}::$perlsym"} = \&{"Shell::$sym"}; } }
Does this seem like a good idea? If not, why not?

Update:
Update 2: Realized I broke the autoloading. Fixed.

Replies are listed 'Best First'.
Re: Possible Improvement to Shell.pm
by moritz (Cardinal) on Jul 08, 2008 at 16:38 UTC
    Does this seem like a good idea? If not, why not?

    As far as I can tell it doesn't deal with name clashes. What happens if you have a command foo_bar and one foo-bar?

    And what's up with all the other meta characters that are allowed in the shell, but not in perl? (I don't know the shell very well, but I could imagine that '+' might be one of those.

      As far as name clashes go: you're explicitly asking for one command, so thats probably the one you want to use. I would also tend to question the sanity of a system that had programs with such similar names yet differing functionality.

      I hadn't thought of '+', because it hadn't come up for me yet. Thanks.

        What happens if you have two commands that get 'perlified' to the same name?

        use Shell 'foo.bar', 'foo-bar';

        Perhaps the import should die in that case. To accomodate this need, perhaps you could allow an explicit mapping?

        use Shell # Command # sub name ['foo.bar' => 'foo_dot_bar' ], [ 'foo-bar' => 'foo_dash_bar'], [ $^O =~ /Windows/ ? 'copy' : 'cp' => 'cp' ];


        TGI says moo

        As far as name clashes go: you're explicitly asking for one command, so thats probably the one you want to use

        Very good. Obviously I don't know enough about Shell.pm, so disregard my comment ;-)

        I would also tend to question the sanity of a system that had programs with such similar names yet differing functionality.

        Me too, but as a module author you're in no position to judge your user's sanity, or the sanity of their systems.

        I hadn't thought of '+', because it hadn't come up for me yet. Thanks.

        If you want to do it properly, either look into the source code of a POSIX compatible shell or in the POSIX standard itself to get a list of all characters that can be used in commands without the need for escaping. On thinking a bit more I remember that there's /usr/bin[ on my system (for stuff like if [ .. ], so there could well be many other allowed characters.

        Maybe just substitute anything but [a-zA-Z0-9_] with underscores?

Re: Possible Improvement to Shell.pm
by Jenda (Abbot) on Jul 09, 2008 at 15:39 UTC

    If you wanted to really extend Shell.pm you might implement something like

    use Shell cmdname => { exe => '/path/to/executable', capture_stderr => 1, params => [ '-foo', \1, '-bar', \2], }; # ... cmdname( $foo, $bar); # calling # /path/to/executable -foo '$foo' -bar '$bar' 2>&1
    or even things like
    use Shell cmdname => { exe => '/path/to/executable', return => 'pid', }, othercmd => { return => 'handle', }; # ... my $pid = cmdname(@params) or die "... $^E"; my $handle = othercmd( @params2); while (<$handle>) { ... } close $handle;