[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [FWP] Command-line mystery



On Tue, Aug 22, 2000 at 10:52:04PM -0400, Jeff Pinyan wrote:
> The following code was causing regex on DALnet #perl much chagrin:
> 
>   $x = { 'a' => \&foo };
>   sub foo { print 'bar' }
>   $x->{a}->();
> 
> For some reason, it did not print for him, yet if he replaced 'bar' with
> "bar", it printed.  It turns out he was doing this at the command-line:
> 
>   perl -e '$x={'a'=>\&foo};sub foo{print 'bar'};$x->{a}->()'
> 
> First I said "silly you, you're using ' as your -e quote character".
> 
> Then I said "why the hell isn't the shell bitching at you?"

Because that's a *feature*. The shell uses unescaped whitespace as
token separators. You can escape whitespace with backslashes, or
quotes. And you don't have surround an entire token with quotes,
just parts of it.

And here's why it's a truely great feature. This is how you would
rename all your .jpg files to .jpeg ones:

    for i in *.jpg; do mv $i `basename $i .jpg`.jpeg; done

`basename $i .jpg`.jpeg makes one token, with only part of it run as
a command.

Ever used (in Perl) strings that both needs interpolation, and $ or @
characters that are followed by letters? You end up either using backwacks
or concatenation. In the Bourne shell or a descendent, you would just
switch quotes.

> Then I ran it through -MO=Deparse, and was shocked when I saw that Perl
> got the ENTIRE code.

Almost right. It's like the shell saw (in Perl terms):

    '$x={' . "a" . '=>\&foo};sub foo{print ' . "bar" . '};$x->{a}->()'

which translates to:

     $x={a=>\&foo};sub foo{print bar};$x->{a}->()

Note the subtle difference. The are no quotes around <a> and <bar>.

>                       But then I noticed that it was doing
> 
>   sub foo {
>     print bar $_;
>   }
> 
> Guh, I said.  Then I realized that the -e gets a single argument, and all
> whitespace must be contained within quotes.

But the whitespace is irrelevant. It's the bareword that tripped Perl.

> whitespace must be contained within quotes.  The much simpler case is:
> 
>   perl -e 'print 'foo''
> 
> This is really
> 
>   perl -e 'print foo'
> 
> since the -e option receives as its argument a quoted string and an
> unquoted string and another quoted string; "print ", foo, and "".

Wrong. Perl is called with just two arguments in this case: <-e> and
<print foo>. -e always takes exactly one argument; never more, never less.
(Although for the shell and the passing of arguments to perl there is
a difference between <perl -e 'print foo'> and <perl -e'print foo'>. In
the former, perl is called with two arguments: <-e> and <print foo>, while
in the latter case, perl is called with one argument: <-eprint foo>. It's
the argument parsing of perl that fixes this.)

>                                                                    If you
> make a tiny adjustment:
> 
>   perl -e 'print 'foo' . 'bar''
> 
> then it prints foobar, but only because Perl sees
> 
>   perl -e 'print foo . bar'
> 
> Of course, had -w been used, bareword warnings (or use of
> uninit. values) would have been elicited.


Right.


Abigail

==== Want to unsubscribe from Fun With Perl?  Well, if you insist...
==== Send email to <fwp-request@technofile.org> with message _body_
====   unsubscribe