Perl script throws syntax error for awk command

Viewed 217

I have a file which contains each users userid and password. I need to fetch userid and password from that file by passing userid as an search element using awk command.

user101,smith,smith@123
user102,jones,passj@007
user103,albert,albpass@01

I am using a awk command inside my perl script like this:

...
...
my $userid = ARGV[0];
my $user_report_file = "report_file.txt";
my $data = `awk -F, '$1 ~ /$userid/ {print $2, $3}' $user_report_file`;

my ($user,$pw) = split(" ",$data);
...
...

Here I am getting the error:

awk:  ~ /user101/ {print , }
awk:  ^ syntax error

But if I run same command in terminal window its able to give result like below:

$] awk -F, '$1 ~ /user101/ {print $2, $3}' report_file.txt
smith smith@123

What could be the issue here?

1 Answers

The backticks are a double-quoted context, so you need to escape any literal $ that you want awk to interpret.

my $data = `awk -F, '\$1 ~ /$userid/ {print \$2, \$3}' $user_report_file`;

If you don't do that, you're interpolating the capture variables from the last successful Perl match.

When I have these sorts of problems, I try the command as a string first to see if it is what I expect:

my $data = "awk -F, '\$1 ~ /$userid/ {print \$2, \$3}' $user_report_file";
say $data;

Here's the Perl equivalent of that command:

$ perl -aF, -e '$F[0]=~/101/ && print "@F[1,2]"' report_file

But, this is something you probably want to do in Perl instead of creating another process:

  • Interpolating data into external commands can go wrong, such as a filename that is foo.txt; rm -rf /.
  • The awk you run is the first one in the path, so someone can make that a completely different program (so use the full path, like /usr/bin/awk).
  • Taint checking can tell you when you are passing unsanitized data to the shell.

Inside a program you don't get all the shortcuts, but if this is the part of your program that is slow, you probably want to rethink how you are accessing this data because scanning the entire file with any tool isn't going to be that fast:

open my $fh, '<', $user_report_file or die;
while( <$fh> ) {
    chomp;
    my @F = split /,/;
    next unless $F[0] =~ /\Q$userid/;
    print "@F[1,2]";
    last; # if you only want the first one
    }
Related