0

I am trying to execute below awk command inside a perl script, but it is failing.

#!/usr/bin/perl

print `awk -F, '{print $NF}' f1.txt > f2.txt`

This is the error:

syntax error at ./MO.pl line 3, near "print"
Execution of ./MO.pl aborted due to compilation errors.

Can anyone please help what I am doing wrong here?

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
Komal
  • 41
  • 1
  • 4
  • 1
    You probably need to escape the `$NF` --> say `\$NF` – fedorqui Feb 24 '15 at 10:16
  • Thanks @fedorqui even after backslash \$NF . I am facing same error as above mentioned in the question – Komal Feb 24 '15 at 10:23
  • Doing a research I found a reference to `%q` in [this question](http://stackoverflow.com/questions/6306386/how-can-i-escape-an-arbitrary-string-for-use-as-a-command-line-argument-in-bash), I would go using `qx`according to [this doc](http://www.cs.cmu.edu/afs/cs/usr/rgs/mosaic/pl-exp-str.html) so this should work: `print qx/awk -F, '{print $NF}' f1.txt > f2.txt/` – Tensibai Feb 24 '15 at 10:34
  • 3
    I'd suggest in this case - that given you're not doing much with `awk` it might be better to keep it in perl. – Sobrique Feb 24 '15 at 11:01
  • 2
    Why do we see so many questions asking how to run awk scripts from perl (and python)? I thought perl at least could do the same text manipulation operations that awk can do, is that wrong? – Ed Morton Feb 24 '15 at 13:39
  • 1
    @EdMorton, you're quite right. – glenn jackman Feb 24 '15 at 14:15
  • @Tensibai, `qx()` will still interpolate the awk variable as a perl variable. It requires escaping. – glenn jackman Feb 24 '15 at 14:16
  • @glennjackman so any idea why we see all the questions asking how to call awk from perl (but, interestingly, never any asking how to call perl from awk AFAIK)? Is it usually people using perl like a shell or something else? – Ed Morton Feb 24 '15 at 14:28
  • 2
    I would say it's people who know shell and awk, and are starting to learn perl -- they stick with the idioms they know rather than jumping into the new language with both feet. – glenn jackman Feb 24 '15 at 14:29

3 Answers3

2

This is a Perl error and has nothing to do with your awk script itself. The error is usually seen when the previous statement doesn't have a semicolon at the end.

Here's a very simple program (which should include use strict; and use warnings;, but I wanted to emulate what you have).

#! /usr/bin/env perl
#

print "Hello, World\n"  # Line 4
print "Hello, Back\n";  # Line 5

And the error message is:

syntax error at test.pl line 5, near "print"
Execution of test.pl aborted due to compilation errors.

Note the error is near the print in Line #5, but the error is actually at the end of Line #4 where I'm missing a semicolon.

Running your exact program works on my system (although doesn't quite produce the results you want). I am assuming this isn't your exact program, but instead a simplification of your program. Is there a statement before that print?

Several other things:

  • You're redirecting your awk output, so there's nothing to print.
  • Use strict and warnings.
  • Better to use qx(....) than backticks (grave accent). It's more readable and allows you to do quoted executable in quoted executable.
  • Watch for Perlisms in your code. The $NF is interpreted by Perl, and without the use strict;, doesn't give you an error. Instead, the print in your Awk statement is a null print which prints the entire line.
  • Why do you use print if nothing is printing out? You're better off in this position to use system which allows you to put single quotes around your entire statement:

    system q(awk -F, '{print $NF}' f1.txt > f2.txt);

    This way, $NF doesn't have to be quoted.

  • Why are you doing Awk in a Perl program? Perl will do anything Awk will do and do it better:

Here's a version of your program using plain ol' Perl:

#! /usr/bin/env perl

use strict;
use warnings;
use autodie;

while ( my $line = <> ) {
    my @array = split /\s*,\s*/, $line;
    print $array[-1];
}

To run this program:

$ test.pl f1.txt > f2.txt

Yes, it's longer, but half of the program is taken up by pragmas that all Perl programs should use.

I'm sure people smarter than me can turn this into a Perl one-liner.

David W.
  • 105,218
  • 39
  • 216
  • 337
1

Since you're redirecting the awk output, there's nothing for perl to print. You might as well use system and the quoting operator q():

system q(awk -F, '{print $NF}' f1.txt > f2.txt)

Or, of course, do it in perl, which saves you from having to spawn a shell and then spawn awk:

open my $in, '<', 'f1.txt';
open my $out, '>', 'f1.txt';
while (<$in>) {
    print $out (split " ")[-1], "\n";
}
close $in;
close $out;
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

If there are more lines in the script, you need a semi-colon at the end of the print statement.

Greg Morris
  • 189
  • 1
  • 11