Shell escaping in Perl

Shell Escaping:

There are several methods for escaping special characters in the Linux shell:

  • Double quotes: Double-quoted strings require escaping of only a few characters.  Example:
    >echo “Some String: &>|\”\$’\`\s\\”
    Some String: &>|”$’`\s\
    This method is useful as long as the string contains few or no characters that are special to the shell.  It also allows embedding all types of quotes.
  • Single quotes: Single-quoted strings require no escaping at all.  Example:
    >echo ‘Some String: &>|”$’\”`\s\’
    Some String: &>|”$’`\s\
    This method is even shorter, but has a major drawback: Strings may not contain single quotes.  To get around this, “glue” is used, where the shell automatically concatenates adjacent strings.  This requires multiple strings, and any single-quote must then be escaped using one of the other methods.
  • Dollar quotes: Dollar-quoting requires minimal escaping and allows all quotes inside.  Example:
    >echo $’Some String: &>|”$\’`\s\\’
    Some String: &>|”$’`s\
    With this method, only single-quotes and backslashes must be escaped.  This method also tolerates unnecessary escaping.
  • Unquoted: Unquoted strings may be used by escaping all special characters.  Example:
    >echo Some\ String:\ \&\>\|\”\$\’\`\s\\
    Some String: &>|$”‘`s\
    The main advantages of this method are that it has a very simple rule-set (escape everything!), and it also tolerates unnecessary escaping.

Perl System Calls:

Perl interacts with the shell in several different ways: system() and exec() calls, back-ticks (“) and the qx// operator, open() pipe’d filehandles, etc.  Often commands include some interpolation of variables, and these variables may contain special characters.  Forgetting to escape such characters can be a security risk, as it’s very easy for special characters (such as semi-colon (;) the command separator, pipe (|) command chaining, greater-than (>) redirection, etc) to sneak their way into a command and wreak havoc.

system(), exec(), and open() calls that use comma-separated arguments (list form) escape automatically, so this is the preferred method of dealing with escaping:

my $var = '&>|"$\'`\s\\';
system ( 'echo', "Some String: $var" );
open ( my $fh, '-|', 'echo', "Some String: $var" );

However, this method does not use the shell (it executes directly using the internal system() function), so shell interpolation is not supported.  This means no piping (|), redirects (>), background (&), etc.

Interpolated (single-string, backticks, and qx//) calls require escaping.  It’s tempting to use one of the various quoting methods listed above and manually escape special characters as needed, but Perl provides functionality that best supports the unquoted escaping method.  The built-in function quotemeta(), and its equivalent interpolation \Q…\E are perfect for this job:

my $var = '&>|"$\'`\s\\';
system ( "echo \QSome String: $var\E" );
open ( my $fh, "echo \QSome String: $var\E|" );
my $result = `echo \QSome String: $var\E`;

Note that shell quoting escaping rules differ from Perl quoting escaping rules – specifically, single quotes in Perl allow embedding single-quotes (as long as they are escaped), interpolation (double-quoting) requires escaping of a different set of characters considered special, and Perl tolerates unnecessary quoting where the shell does not.

Nesting:

Nesting strings that require escaping can be daunting some times…  Consider this command:
>sh -c “echo \”Some String: &>|\\\”\$’\\\`\s\\\\\””
Some String: &>|”$’`\s\
This double-escaping mess can be reduced somewhat by using different quotes, but applying the right rules will give you a headache:
>sh -c ‘echo “Some String: &>|\”\$’\”\`\s\\”‘
Some String: &>|”$’`\s\

Fortunately, Perl’s quotemeta() takes care of all this, so nesting is straightforward:

my $var = '&>|"$\'`\s\\';
system ( "sh -c \Qecho \QSome String: $var\E\E" );

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>