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

動作する2つの方法のうち、特に入れ子に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

Busyboxでは、awk最後の2つのオペランドの周りに括弧が必要なようです。

同じエラーが発生します。

$ 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 : 22

一方、割り当てられたターゲットを条件に応じて変更するには、次の手順を実行します。本当にそうしなければならない明確にするために、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

関連情報