[sf-perl] Perl in shell

David Alban extasia at extasia.org
Mon May 14 10:04:39 PDT 2007

Following up on the recent thread regarding embedding perl in shell code...

Sometimes you're maintaining/enhancing a piece of shell code for which
you don't have the option to convert it to perl.

I recently needed to validate a unix permissions string from within a
bash program.  I chose to embed the perl code rather than put it in an
external file.  The perl code is not terribly complex, and shouldn't
need to change very much.

I write perl rather than shell when I have the choice, but I don't
think embedding perl in shell is necessarily a bad thing.

It's not difficult to use shell variables in perl.  For example:



  perl -e '
    my $var = q{'"$foo"'};
    print "$foo\n";

This assigns the shell's value of $var to a perl variable named $var
and prints the value.

Let's look at the quoting to get the shell value:

  my $var =
            [a] q{
              [b] SINGLEQUOTE
                [c] DOUBLEQUOTE
                [c] DOUBLEQUOTE
              [b] SINGLEQUOTE
            [a] }

[a] is a method you might use to quote your value in perl:

  my $var = q{foo};

Here we definitely use it to improve readability.

Quotes [b] cause a brief respite from the singly quoted portion of the
embedded perl code, so that we may reference values in shell

Quotes [c] are double quotes in the shell.  They are the quotes you'd use in:

  echo "$var"

Note that by defining "my $var ...", I use The Ugly Shell
Interpolation for Use in Embedded Perl Code Quoting Method(TM) only to
assign the shell value to the perl variable.  I don't try embedding
that quoting in, say, the print statement, or in other more complex

Here's my shell function to check the validity of a numeric unix perms string:

perms_are_valid () {

  perl -e '
    use strict;
    use warnings;

         # get candidate perms string from shell
    my $perms = q{'"$candidate_perms"'};

         # must be three or four chars long
    my $perms_length = length $perms;
    $perms_length != 3 and $perms_length != 4 and exit 1;

         # if four characters in length, first char must be in [01234]
    if ( $perms_length == 4 ) {
      my ( $first_char, $dontcare ) = unpack "A1A*", $perms;
      $first_char =~ m{ [^01234] }xms and exit 1;
    } #

         # can contain only octal digits
    $perms =~ m{ [^0-7] }xms and exit 1;

    exit 0

  return $perms_validated
} # perms_are_valid

When invoked using:
  for i in 0 foo 2 002 111 400 0755 0855 0779 0664 2755 4755 5755; do
    if perms_are_valid "$i" ; then
      results="    valid"
      results="NOT valid"

    printf "%6s %s\n" "$i:" "$results"

We get:

    0: NOT valid
  foo: NOT valid
    2: NOT valid
  002:     valid
  111:     valid
  400:     valid
 0755:     valid
 0855: NOT valid
 0779: NOT valid
 0664:     valid
 2755:     valid
 4755:     valid
 5755: NOT valid

(One could argue for allowing one- and two-character perms strings,
but for my purposes I chose not to allow it.)


P.S.  One last note.  Be sure not to use single quote characters in
comments in the embedded perl!  It only takes one instance of a
comment like the following (note the single quote hiding as an
apostrophe) to cause Badness(TM):

  # we don't want foo to be greater than bar

Live in a world of your own, but always welcome visitors.

More information about the SanFrancisco-pm mailing list