为什么 awk 'NR%2 == 1?ORS=";":ORS="\n"' 给出语法错误?

为什么 awk 'NR%2 == 1?ORS=";":ORS="\n"' 给出语法错误?

我正在解决一个 Hackerrank 问题,输出是

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

用于输入

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

我正在用来ORS执行上述任务。但不知道为什么会出现运行时错误?

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

出现的错误是

awkNR: cmd. line:1: Possible syntax error

答案1

不带括号的三元表达式会在各种上下文中的各种 awk 版本中导致语法错误,而不仅仅是已经提到的上下文和 awk 版本。这是 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

在两个有效的方法中,我发现print (1 == 2 ? 3 : 4)更具可读性,特别是当您获得嵌套三元组时:

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

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

所以这就是我经常使用的,并且在有用的条件周围添加括号,通常是为了可读性。

由于带括号的三元数总是比不带括号的三元数更容易阅读,因此根本没有充分的理由编写不带括号的三元数。

你也不应该在条件上下文中使用赋值,除非你需要赋值的结果将作为条件进行评估,但您不需要。

你想要做的应该写成:

$ awk '{ORS=(NR%2 ? ";" : RS)} 1' file
A 25 27 50;B 35 37 75
C 75 78 80;D 99 88 76

答案2

Busyboxawk似乎需要在最后两个操作数周围加上括号。

我得到同样的错误

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

但它适用于

$ 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

重写以避免尴尬的引用字符串,您的构造如下:

1 > 0 ? a = 1 : a = 2

它并不完全含糊,因为它只能像(1 > 0) ? (a = 1) : (a = 2).但根据 POSIX,赋值的优先级低于条件运算符 ?:,所以 Busybox 可能会尝试像 一样解析它(1 > 0 ? a) = (1 : a) = (2),但这实际上不起作用。

它在 C 语言中也不起作用(Debian 的 gcc 6.3.0-18+deb9u1),所以我不会说 Busybox 在这里完全错误:

/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;
                        ^

(我想 stackoverflow 的语言律师可以准确地告诉我们为什么以及如何应该或不应该这样做。)

您可以在作业周围添加括号,但是应该写成a = 1 > 0 ? 11 : 22.这就是赋值的优先级确实低于 的原因?:,如果没有,则会解析为(a = (1 > 0)) ? 11 : 22which 通常不是您想要的。

另一方面,如果您希望分配的目标根据条件而改变,您可以真的应该为了清楚起见,请使用完整的if句子而不是1 > 0 ? (a = 11) : (b = 22)

答案4

也许 :

echo "${cccccccc}"
echo
echo "${cccccccc}" \
\
| mawk -F. 'ORS=substr(";\n",_-(NR%_--),NF=_++)' \_=2 OFS= | ecp

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

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

甚至更简单 - 使用大量内置变量来完成繁重工作的解决方案:

mawk -F. 'NF=sub(FS,(NR % _)?":" :"\n",ORS)' OFS='' \_=2

如果您更喜欢某种getline方法,那么您甚至不必花费精力来计算NR % 2

 echo;  echo "${cccccccc}"
 echo;  echo "${cccccccc}" \
 \
 | mawk -F. '$!_=$-_=sprintf("%s;%s",$( NF ^= !NF ),
                                     $!(NF  = getline))' OFS=''

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

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

如果你真的很喜欢奇特的语法,甚至可能

mawk -F. 'sub("^",($!(NF = !_))";",$!(NF = getline))' OFS=


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

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

相关内容