Я пытаюсь понять, как awk
работает с переменными в операторах if
.
Вот текстовый файл игрушки:
$ cat myscript.sh
#! /bin/bash
set -eu
set -o pipefail
IFS=$'\n\t'
for arg in $@; do
echo "do something with file $arg"
done
Теперь я хочу awk
напечатать самую длинную строку в файле.
Я думал сделать так:
$ awk '{max = 0}{if (length($0) > max) {max = length($0)} else {}} END {print max}' myscript.sh
Но это напечатает длину последней строки. Однако, когда я запускаю следующее:
awk '{if (length($0) > max) {max = length($0)} else {}}END{print max}' myscript.sh
Результат правильный, и он печатает правильную длину 35
.
Я действительно не могу понять, почему, когда я указываю переменную max
перед оператором if
, условие не распознается.
Я уверен, что есть простое объяснение awk-gurus
, но лично я его не вижу.
Спасибо
Я просто использовал ее как фиктивную переменную, а затем присваиваю ей следующие значения, если length
если она длиннее, чем предыдущее max
значение. Эта логика верна?
awk 'length() > max{max = length()} END{print max}' file
короче.
Спасибо, вот это я не понимаю, где мне определять переменную max
? или в этом нет необходимости?
Нет, не нужно определять это. Если вы действительно хотите инициализировать какую-либо переменную, поместите ее в блок BEGIN
.
Вы можете немного изменить первую команду, чтобы она работала:
awk 'BEGIN{max = 0}{if (length($0) > max) {max = length($0)} else {}} END {print max}' myscript.sh
Таким образом, вы инициализируете переменную max в начале скрипта. Без оператора BEGIN max обновляется до 0 в каждой строке.
Однако переменные awk имеют значения по умолчанию, которые зависят от контекста. Вы можете прочитать это, чтобы понять логику.
Variables in awk can be assigned either numeric or string values. The kind of value a variable holds can change over the life of a program. By default, variables are initialized to the empty string, which is zero if converted to a number.
С помощью этой команды:
awk '{if (length($0) > max) {max = length($0)} else {}}END{print max}' myscript.sh
Awk инициализирует max значением 0 в первой строке, потому что вы сравниваете его с длиной ($0), которая является целым числом.
wrt Awk will initialize max to 0 at the first row because you are comparing it to length($0) which is an integer.
- нет, не будет. Если это так, то запуск этой команды для пустого файла выведет 0
, но вместо этого выведет нулевую строку. Когда length($0) > max
выполняется впервые, max
имеет тип числовой строки со значением ноль или ноль, это сравнение, который обрабатывается как числовой, поскольку он сравнивает число с числовым значением, но max
не меняет свой тип или значение при эта точка.
Попробуйте запустить эти команды, чтобы увидеть это: seq 2 | awk '{print "max = " ( (max == 0) && (max == "") ? "zero-or-null" : max ); max=0}'
и seq 2 | awk '{print "max = " ( (max == 0) && (max == "") ? "zero-or-null" : max ); max = ""}'
. В gawk вы можете просто напечатать typeof(max)
, чтобы увидеть его тип в любой момент, например. echo "" | awk '{if (length($0) > max) {max = length($0)} print typeof(max)}'
выведет unassigned
.
@Corentin уже объяснил вашу проблему, поэтому вы должны оставить его / ее ответ как принятый, но просто к вашему сведению, правильный способ напечатать длину самой длинной строки в файле таков:
awk '{cur=length()} cur>max{max=cur} END{print max+0}' myscript.sh
Это гарантирует, что max будет числом, даже если все строки пусты, не вызывает length() несколько раз в строке и гарантирует, что вы получите числовой вывод, даже если ввод пуст (точно так же, как wc
делает для пустых файлов).
{max = 0}
в первом коде устанавливаетmax
на ноль перед каждой записью.