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

I've a question regarding the usage of backquotes. Here is the code:
$good = `grep -i $vals[0] $file | awk '{ print $2 }'`
You can see I'm trying to get specific output with an awk statement. It doesn't seem to like the quoted statement. I've tried inserting backslashes with no luck. I am forced to put the awk statement in a file and call it like so:
$good = `grep -i $vals[0] $file | awk -f myprint`
What am I missing? Is there a better way. Thanks.

2004-05-05 Edit by jdporter: Changed title from 'backquotes'

Replies are listed 'Best First'.
Re: Unwanted interpolation in backquoted string
by Roger (Parson) on May 04, 2004 at 06:41 UTC
    You should escape the "$2" with backslashes otherwise it gets interpolated by perl.

    A better way? Umm, that depends on the point of view. To me, a better way is a perl only way to minimize dependency on external programs and platform independent as well. So instead of using external programs, I would do it in perl.

    use IO::File; ... my $good = getvalue($file, $vals[0]); ... sub getvalue { my ($file, $val) = @_; my $val; my $f = new IO::File $file, "r" or die "Can not open file"; while (my $line = <$f>) { if ($line =~ /$val/) { return (split /,/, $line)[1]; # return 2nd field } } return undef; }
      Your "pure-perl" alternative is not exactly equivalent to the OP. First, by default "awk" splits on white-space, just like the default behavior of "split" (so you shouldn't be splitting on commas). Second, if "$file" contains multiple lines that match $vals[0], the OP's backtick version will return a string with multiple lines, whereas your code will only return at most a single line. (Oh, and why do you have "my $val" a second time?) To replicate the "grep | awk" pipeline properly, the sub would actually be simpler:
      sub getvalue { my ($file, $val) = @_; my $f = new IO::File $file, "r" or die "Can not open $file: $!"; my $matched = ''; while (<$f>) { $matched .= (split)[1] . "\n" if (/$val/); } return $matched; }
        Or even simpler.
        $good = do { local @ARGV = ($file); join '', map { /$vals[0]/i ? (split)[1]."\n" : () } <>; };
        I was just giving an idea on how this could be done, not on the absolute correctness of the code though.

      Ahhh. Of course. Thanks much.
Re: Unwanted interpolation in backquoted string
by sgifford (Prior) on May 04, 2004 at 06:44 UTC

    The $2 is being interpreted by perl. Put a backslash before it and you should be good to go.

    Turning on warnings is what gave me the hint to tell me why this wasn't working.

Re: Unwanted interpolation in backquoted string
by coec (Chaplain) on May 04, 2004 at 06:46 UTC
    Something like
    open(FILE, $file) or die "$!"; my @file = <FILE>; close(FILE); foreach (@file) { if (m/$val[0]/) { $tmp = (split /\s+/,$_)[1]; print $tmp . "\n"; } }

    but the actual problem with the back quotes is that $2 should be escaped. (s/$2/\$2/) The reason is that you want awk to interpret $2, not Perl.

    CC

    Note that this is completely untested...

      I think you mean s/\$2/\\\$2/ :)
        Doh!