Почему awk ведет себя иначе для $1, если значение равно 0 (ноль)?

Используйте sedи вам нужно было избежать \, так как это специальный символ:

sed 's/"/\\"/g' infile
5
05.04.2020, 19:09
4 ответа

Из Руководства пользователя GNU Awk:

An assignment is an expression, so it has a value—the same value that is assigned. Thus, ‘z = 1’ is an expression with the value one.

Так

  • echo 0 | awk '$1=$1'шаблон оценивается как 0 (FALSE)

  • echo 1 | awk '$1=$1'шаблон оценивается как 1 (ИСТИНА )и выполняется действие по умолчанию print

16
28.04.2021, 23:18

Я не думаю, что это вопрос числового значения :стандартные преобразования позаботятся об этом (здесь, по крайней мере ).

OP показывает четыре разных кода awk, все варианты :шаблон { действие }

(a )1 доллар = 1 доллар

Это переназначает себе 1 доллар. Это не логический тест, это не -операция (эффективно ), и он возвращает значение $1. Если $1 равно 0, шаблон false и действие печати по умолчанию полностью пропускается . Если $1 не равен -нулю, ввод печатается .

(b ){ $1 = $1; Распечатать; }

Это переназначает себе 1 доллар, а также нет -op. При отсутствии шаблона действие выполняется, и ввод всегда печатается .

(c )$1 == $1

Это логическое выражение, которое всегда истинно . 0 равно 0, 1 равно 1 (, а трубкозуб есть трубкозуб ). В отсутствие действия ввод всегда печатается .

(d ){ $1 == $1; Распечатать; }

Шаблона нет. Сравнение дает истинное логическое значение, которое отбрасывается. Ввод всегда печатается .

7
28.04.2021, 23:18

простые случаи

Давайте сначала упростим.

Что делает код awk '$1=$1', можно понять, распечатав значение $1=$1. А также то, что делает код awk '$1==$1', можно понять, напечатав его значение. Оба подпадают под определение awk:

pattern   { action }

Если часть действия отсутствует, выполняется действие по умолчанию print. Таким образом, awk '1'напечатает все входные строки. awk '0'ничего не напечатает.

Таким образом, значение $1=$1 и $1==$1 будет напечатано этим:

$ printf '%s\n' 0 1 | awk '{print $1=$1, $1==$1}'
0 1
1 1

Следовательно, для ввода 0шаблон $1=$1будет не печатать строку ввода. Для1(и любого другого целочисленного значения )будет.

$1==$1просто :это (почти [а])всегда верно.

Другие представленные вами параметры awk '{...,print}'всегда будут печататься, потому что шаблона нет, и по умолчанию выполняется код внутри фигурной скобки, и (если нет команды для выхода из awk )последнее действие:printвсегда будет выполняться.

Из четырех различных вариантов, которые вы предлагаете, только когда ввод 0и код awk '$1=$1', ввод будет напечатан , а не . Именно то, что у вас есть.

более сложный

Кажется, обсуждается, что это должно делать:

echo 0 | awk '$0="0"'      # true as "0" is a non-null string.

Имеет строку "0", назначенную всему вводу ($0), вывод такого назначения также является строкой("0").Строка, содержащая что-либо, кроме null, означает true . Итак, да, это напечатает ввод, но не потому, что это число 0, а потому, что это строка "0".

Когда конвертировать

Значения переменных в awk имеют двойной тип :числа и строки.

Значение переменной может быть указано явно в написанном коде, например

awk '{a=1234; b=1e-3; c="string"; d="1234"}'

Присвоение числовых значений создает числовую переменную.
Присваивание строке внутри кавычек "..." генерирует строковую переменную.

Итак, c и d — это строки, а a и b — числа (, которые могут быть получены путем двух преобразований :integer (strtod )и float (strtof)).

Проблема начинается, когда переменная получает «пользовательский ввод», например, когда поле читается в первый раз. Что echo 000 | awk '{print $1}'должно печатать:000или 0? это числовое значение 0или строка 000, которая выглядит как число?.

Здесь начинается преобразование, преобразование требуется как для получения числа из строки, так и для получения строки (, которую можно было бы сравнить )из числа. В общем, только «пользовательский ввод» нуждается в преобразовании, предполагается, что написанный код содержит правильный тип (либо a=123, либо a="123" ). И преобразования могут быть вызваны добавлением нуля (var+0 )или объединением (возможно пустой )строки (var"" ).

проблемные случаи

[а]

  1. Строка всегда равна самой себе, несмотря ни на что.
  2. Числовое значение всегда равно самому себе, кроме случаев, когда оно равно nan(иногда ).

    Даже если $1является nan (+inf -inf, или 0*inf, или некоторыми другими ), большинство реализаций awk (nawk, mawk, оригинальный -awk и bsd awk )будут утверждать, что $1==$1 верно. Это противоречит спецификации IEEE754,который требует, чтобы NaN не был равен чему-либо. Итак, это ошибка awk (большинства awk ). За исключением busybox awk, который не утверждает, что $1==$1является истинным, если $1 равен -nan, я не могу подтвердить, что это сделано по замыслу, поскольку я не просматривал их исходный код.

    echo '-nan' | awk '$1==$1'
    

    Таким образом, это правда, что приведенный выше код будет считать $1==$1истинным, но это может (стать )неверным в будущем.

  3. Требуется преобразование.

    Если сравниваются две строки или два числа, преобразование не требуется.
    При смешанном типе необходимо выполнить преобразование.
    Что обычно реализовано, так это то, что если строка выглядит как число ("123")(, называемое strnum в GNU awk )и поступает из внешнего ввода (формы кодовых значений, преобразование по умолчанию не выполняется ), затем оно преобразуется в число и a==bвыполняется численно. В противном случае сравнение выполняется как строки.

Так:

echo 0 | awk '$0="0"'

Всегда является строкой("0")и результатом является истина.

Но:

echo 0   | awk '$0'
echo 000 | awk '$0'

оба являются «внешними входными данными», а выглядят как число , поэтому оба преобразуются в числа, и поскольку значение 0или 000является числовым 0, результат шаблон false и оба не будут напечатаны.

За исключением , опять же, если входное значение является числовымNaN(да, числовым )и ошибка в awk, заключающаяся в несоблюдении IEEE754, исправлена, тогда это, что печатается во многих реализациях awk:

echo '-nan' | awk '$0'

может остановить печать.

Обратите внимание, что это происходит во FreeBSD:

$ echo 'test -nan' | 
    original-awk '{print $2,($2==1),($2==0),$2+0,$2*0,($2==$2)}$2'
-nan 1 1 -nan -nan 1

A -nanравно 1 и равно 0 и не печатает test.

2
28.04.2021, 23:18

Поскольку $0 — это вся запись(полная строка ), $1, $2 — это поля (, обычно разделенные пробелами ).

4
28.04.2021, 23:18

Теги

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