[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:
#!/bin/bash
var=foo
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
$foo
[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
variables.
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
statements.
Here's my shell function to check the validity of a numeric unix perms string:
#-----------------------------------------------------------------------
perms_are_valid () {
candidate_perms="$1"
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
'
perms_validated=$?
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"
else
results="NOT valid"
fi
printf "%6s %s\n" "$i:" "$results"
done
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.)
David
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