http://qs321.pair.com?node_id=438860

Willworker has asked for the wisdom of the Perl Monks concerning the following question:

I've been fiddling with perl for a while, and am finding more and more occasion to write perl one-liners. The problem is that I keep getting confused as to what characters I need to escape in my program string so that the shell doesn't do evil things with them. Has someone got a link to a reference for this sort of thing?

Steve

2005-03-12 Edited by Arunbear: Changed title from 'Easy question', as per Monastery guidelines

Replies are listed 'Best First'.
Re: Escaping characters in one-liners
by Tanktalus (Canon) on Mar 12, 2005 at 02:33 UTC

    Technically, this is more of a shell question than a perl question. That said, I can understand that it is highly relevant to perl programmers since we seem to take huge pride in our one-liners. ;-)

    For Bourne-shell and derivitives (such as ksh and bash), you simply need to put your program in single quotes, and not use single quotes inside your program.

    I think it's the same for C-shell, but I'm not really a C-shell expert.

    For CMD.EXE (both Win32 and OS/2), you need to use double quotes, and not use double quotes inside your program. Since double quotes interpolate everything, you may want to. Don't - use $/ instead of "\n", e.g., perl -e "print 'foo', $/". For other interpolation, use qq, e.g., perl -e "print qq(foo\n)". You also want to be careful with percent signs - avoid them if you can. If you can't, I think doubling them works - %% probably is replaced with a single %.

    I'm sure others will expand on this - but I've not had any need of more than this. I rarely use Windows, and when I have to, I don't need to do any modulos or print percent signs.

Re: Escaping characters in one-liners
by saintmike (Vicar) on Mar 12, 2005 at 08:07 UTC
    Getting the quotes right can be quite daunting, that's why there's help via Sysadm::Install from CPAN: Let's whip up a script one_liner really quickly:

    #!/usr/bin/perl # one_liner - produce a perl one-liner out of perl code use Sysadm::Install qw(:all); my $in = join "", <>; $in =~ s/\n/ /g; print "perl -e ", qquote($in, ':shell'), "\n";

    Now, if you call one_liner without arguments, it'll wait for code to be typed into STDIN, terminated by CTRL-D, and spit out the one-liner right after:

    $ one_liner print "hello\n"; print "world\n"; ^D perl -e "print \"hello\\n\"; print \"world\\n\"; "

    Produces properly escaped one-liners out of any messy perl code you paste in.

Re: Escaping characters in one-liners
by PodMaster (Abbot) on Mar 12, 2005 at 09:48 UTC
Re: Escaping characters in one-liners
by eXile (Priest) on Mar 12, 2005 at 02:48 UTC
    For bourne-shell-likes you use single quote ('), as mentioned in previous post. If you want to print single quotes from within your one-liner, you can use
    print chr(047)
    Makes it harder to keep your code on 1 line though ...
Re: Escaping characters in one-liners
by mrpeabody (Friar) on Mar 12, 2005 at 18:19 UTC
    On all platforms, you can avoid using particular quoting characters inside your program by using the generic quoting constructs q() and qq().

    For instance, to single-quote something in bash:

    perl -we'my $c=400; print q(not interpolated: $c)'

    This is even more useful in Win32, where you need to avoid the much more common doublequotes:

    perl -we"my $c=400; print qq(interpolated: $c)"

    You can also delimit on something besides parentheses, but parens are easy to read and not disallowed by anything, so I rarely bother.

    See perlop under q/STRING/.

Re: Escaping characters in one-liners
by jhourcle (Prior) on Mar 12, 2005 at 23:37 UTC

    The particular characters that you need to escape are dependent upon the shell, not on perl. For the most part, you can just encase the perl string to be evaluated in single quotes in a unix shell, and make sure that you don't use single quotes in your perl. (I don't know about windows quoting) :

    perl -e 'whatever to execute;'

    You can also use -l (that's a lower case L), so you can send a command quickly without the shell messing with it. (but again, this won't work in the times when you want the shell to do its magic, and it also keeps you from using the shell's abilities to repeat the command).

    If there are times when you want to use shell variables in your line, you can either export them and reference them in perl as $ENV{"NAME"} rather than $NAME or you can end the quoting, use the variable, and then start it back up again:

    perl -e 'print "you are logged in as $ENV{USER}\n";' perl -e 'print "you are logged in as '$USER'\n";'

    The only thing that's really tricky is when you're trying to mix perl and shell commands ... which I'd advise not doing from the shell, as you can't always be sure of the output, and calling it from within perl.

Re: Escaping characters in one-liners
by gam3 (Curate) on Mar 12, 2005 at 18:33 UTC
    I Think this shows the general solutions.
    perl -e 'printf( qq(%s\n"), q("This is a string @#$%^%&*/\\) . q[()] . chr(047) . qq("))'
    A picture is worth a thousand words, but takes 200K.
Re: Escaping characters in one-liners
by Anonymous Monk on Mar 15, 2005 at 01:23 UTC
    Some shells let you "escape" single quotes; others don't. I remember being confused enough about csh's quoting rules that I switched to bash; which at the time and on the systems I was using were documented in a way that made sense to me. In particular, remembering to escape the '!' symbol was annoying until I switched; even wrapping it in single quotes didn't stop history expansion.

    The bottom line is that you have to read your shell's manpage. If you don't like what you read, switch shells. If you can't switch shells, well, grumble, and deal with what you've got.

    The best reference I can give you is to type "man <your_shell_name_here>".