Почему awk 'NR%2 == 1?ORS=";":ORS="\n"' выдает синтаксическую ошибку?

Я также обнаружил ту же проблему, я продолжал играть с сетевым -менеджером -openconnect -gnome, пока соединение не начало работать. Выигрышным шагом для меня было отключение IPv6 для VPN.

2
25.05.2020, 12:59
3 ответа

Busybox awk, по-видимому, нуждается в круглых скобках вокруг двух последних операндов.

Я получаю ту же ошибку с

$ 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
7
18.03.2021, 23:33

Троичные выражения без скобок вызывают синтаксические ошибки в различных версиях 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
12
18.03.2021, 23:33

Переписано, чтобы избежать неудобных строк в кавычках, ваша конструкция выглядит так:

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).

-1
18.03.2021, 23:33

Теги

Похожие вопросы