2

I am solving a Hackerrank question where the output is

A 25 27 50;B 35 37 75
C 75 78 80;D 99 88 76 

for input

A 25 27 50
B 35 37 75
C 75 78 80
D 99 88 76.

I am using ORS to do the above task. But I don't know why runtime error is coming?

awk 'NR%2 == 1?ORS=";":ORS="\n"'

Error coming is

awkNR: cmd. line:1: Possible syntax error
4
  • 2
    There is no error in the code that you show. Please double check that you have copied the exact awk code that you say you're using. Tested with GNU awk, mawk and OpenBSD awk, all produce the correct output. – Kusalananda May 24 '20 at 20:22
  • 1
    Also make sure that you know how the awk code was being executed. If your awk command was stored in a file used with awk -f, then there would have been an issue with it if it was written exactly as you have shown (it's a shell command, not an awk command). – Kusalananda May 24 '20 at 20:24
  • I am running exactly the same code on hackerrank editor. The problem is provided on this link hackerrank.com/challenges/awk-4/problem SIr, can you run the above command and see the error comming. – Shubham Kumar May 24 '20 at 20:30
  • I am getting confused is there problem in the editor or with the code? – Shubham Kumar May 24 '20 at 20:37
7

Busybox awk seems to need parentheses around the last two operands.

I get the same error with

$ busybox awk 'NR%2 == 1?ORS=";":ORS="\n"' file
awkNR: cmd. line:1: Possible syntax error

but it works with

$ busybox awk 'NR%2 == 1?(ORS=";"):(ORS="\n")' file
A 25 27 50;B 35 37 75
C 75 78 80;D 99 88 76
3
  • Adding parentheses is solving the issue. But I am still confused why the error came with the original code? Should I conclude Hackerrank editor uses Busybox awk version in the backend? – Shubham Kumar May 24 '20 at 20:52
  • I don't know Hackerrank, so can't really tell, but it looks like it. – Freddy May 24 '20 at 21:04
  • Hackerrank is coding practice platform based in India. The link to the question is hackerrank.com/challenges/awk-4/problem . Since parentheses is solving the error maybe they are using busybox version only. Thank You for the help. – Shubham Kumar May 24 '20 at 21:08
12

Unparenthesized ternary expressions cause syntax errors in various awk versions in various contexts, not just the context and awk version already mentioned. Heres another example on MacOS:

$ awk --version
awk version 20070501

$ awk 'BEGIN{print 1 == 2 ? 3 : 4}'
awk: syntax error at source line 1
 context is
    {print 1 >>>  == <<<
awk: illegal statement at source line 1
awk: illegal statement at source line 1

$ awk 'BEGIN{print (1 == 2 ? 3 : 4)}'
4

$ awk 'BEGIN{print (1 == 2) ? 3 : 4}'
4

Of the 2 that work, I find print (1 == 2 ? 3 : 4) the more readable, especially when you get nested ternaries:

$ awk 'BEGIN{print (1 == 2 ? (6 == 7 ? 8 : 3) : 4)}'
4

$ awk 'BEGIN{print (1 == 2) ? (6 == 7) ? 8 : 3 : 4}'
4

so that's what I always use and the additionally add parens around just the conditions if/when useful, usually for readability.

Since parenthesized ternaries are always easier to read than unparenthesized, there's simply no good reason to ever write one without parentheses.

You should also never use an assignment in a conditional context unless you need the result of the assignment to be evaluated as a condition, which you don't.

What you're trying to do should be written as:

$ awk '{ORS=(NR%2 ? ";" : RS)} 1' file
A 25 27 50;B 35 37 75
C 75 78 80;D 99 88 76
1
  • At least Busybox does parse {ORS = NR%2 ? ";" : RS} correctly, though. What's easier to read is personal, of course :) – ilkkachu May 25 '20 at 10:07
-1

Rewritten to avoid the awkward quoted strings, your construct is like this:

1 > 0 ? a = 1 : a = 2

It's not exactly ambiguous, since it can only be usefully parsed like (1 > 0) ? (a = 1) : (a = 2). But according to POSIX, the assignment has lower priority than the conditional operator ?:, so Busybox may be trying to parse it like (1 > 0 ? a) = (1 : a) = (2), which doesn't really work.

It also doesn't work in C (Debian's gcc 6.3.0-18+deb9u1), so I wouldn't say Busybox is entirely wrong here:

/tmp$ cat ternary.c
int main(void)
{
    int a;
    1 > 0 ? a = 11 : a = 22;
}
/tmp$ gcc -Wall -o ternary ternary.c 
ternary.c: In function ‘main’:
ternary.c:4:24: error: lvalue required as left operand of assignment
     1 > 0 ? a = 11 : a = 22;
                        ^

(I suppose the language lawyers at stackoverflow could tell exactly why and how that should or should not work.)

You could add the parenthesis around the assignments, but that should be written as a = 1 > 0 ? 11 : 22. This is the reason assignment does have lower precedence than ?:, if it didn't, that would parse as (a = (1 > 0)) ? 11 : 22 which usually isn't what you want.

On the other hand, if you were to want the target of the assignment to change based on the condition, you really should use a full if sentence for clarity instead of 1 > 0 ? (a = 11) : (b = 22).

2
  • Without parenthesis is correctly working in GNU Awk, OPENBSD awk. I think precedence is not the issue. – Shubham Kumar May 26 '20 at 4:46
  • @ShubhamKumar, my point was that it might not be correct. But looking more closely at the grammar, I may be wrong. – ilkkachu May 26 '20 at 7:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.