как извлечь максимальное и минимальное значение из столбца 1 и столбца 2

VALUE=<

Нет вывода.

Здесь -документ является перенаправлением , вы не можете перенаправить в переменную.

При синтаксическом анализе командной строки перенаправления обрабатываются отдельно от назначения переменных. Поэтому ваша команда эквивалентна (обратите внимание на пробел)

VALUE= <

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

Обратите внимание, что

<

действителен, как и

Просто нет команды, стандартный входной поток которой может содержать данные, поэтому он просто потерян.

Хотя это сработает:

VALUE=$(cat <

Здесь команда, которая получает здесь документ -, называется catи копирует его в свой стандартный вывод. Это то, что затем присваивается переменной посредством подстановки команд.

В вашем случае вместо этого вы могли бы использовать

python -m json.tool <

без дополнительного шага по сохранению данных в переменной.


Возможно, стоит изучить такие инструменты, как jo, для создания данных JSON с правильной кодировкой:

Например:

jo type=account customer_id=1234 customer_email=jim@gmail.com random_data="some^Wdata"

... где ^W— литерал Ctrl+W , выведет

{"type":"account","customer_id":1234,"customer_email":"jim@gmail.com","random_data":"some\u0017data"}

Таким образом, команду в вопросе можно было написать

jo type=account customer_id=1234 customer_email=jim@gmail.com |
python -m json.tool
1
11.06.2020, 17:16
6 ответов

Проблема в вашем коде,

awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat

... заключается в том, что вы сразу exitпосле обработки первой строки ввода. Ваш средний блок должен запускаться для каждой строки . Затем в блоке ENDвы можете распечатать найденные значения. Вы делаете это в другом фрагменте кода:

awk '{if ($1 > max) max=$1}END{print max}'

Другая проблема заключается в том, что вы инициализируете minмагическим числом (9 в первом коде, который я цитировал, и 0 во втором фрагменте; переменные, не инициализированные явно, имеют значение 0, если вы используете их в вычислениях ). Если это магическое число не попадает в диапазон чисел в фактических данных, то рассчитанные минимальные и/или максимальные значения будут неверными. Лучше инициализировать как min, так и max некоторым значением, найденным в данных.

Чтобы отслеживать как минимальное, так и максимальное значения, вам нужны две переменные, и обе из них необходимо сверять с данными в файле для каждой строки, чтобы увидеть, нуждаются ли они в обновлении.

Поскольку awkподдерживает массивы, было бы естественно использовать массивы для minи maxс одним элементом массива на столбец. Это то, что я сделал в коде ниже.


Обобщается на любое количество столбцов:

NF == 0 {
        # Skip any line that does not have data
        next
}

!initialized {
        # Initialize the max and min for each column from the
        # data on the first line of input that has data.
        # Then immediately skip to next line.

        nf = NF

        for (i = 1; i <= nf; ++i)
                max[i] = min[i] = $i

        initialized = 1
        next
}

{
        # Loop over the columns to see if the max and/or min
        # values need updating.

        for (i = 1; i <= nf; ++i) {
                if (max[i] < $i) max[i] = $i
                if (min[i] > $i) min[i] = $i
        }
}

END {
        # Output max and min values for each column.

        for (i = 1; i <= nf; ++i)
                printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}

Учитывая этот скрипт и данные в вопросе:

$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334

Условие NF == 0для первого блока (, которое выполняется для всех строк ), должно обеспечивать пропуск пустых строк. Тест означает "если нет полей (столбцов )данных в этой строке". Переменная initializedбудет равна нулю с самого начала (логически ложь ), но будет установлена ​​в единицу (логически истина ), как только первая строка с данными будет читать.

Переменная nfинициализируетсяNF(числом полей )в строке, из которой мы инициализируем значения minи max.Это сделано для того, чтобы вывод в блоке ENDработал, даже если в последней строке нет полей.

3
19.03.2021, 02:29

Использованиеdatamashиprintf:

for f in 1 2 ; do  printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
                   $(datamash -W max $f min $f < file.dat); done

...или без петли:

printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
       $(datamash -W max 1 min 1 max 2 min 2 < file.dat | 
         tr -s '\t' '\n' | paste - - | nl)

Выход одного из:

Column #1
max - 0.4916
min - 0

Column #2
max - -23.4334
min - -24.1254
2
19.03.2021, 02:29

На самом деле можно объединить все инструкции в одну awkпрограмму:

awk 'NR==1{min1=max1=$1;min2=max2=$2}\
     NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
            if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
     END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat

Это инициализирует минимальное и максимальное значения для обоих столбцов с соответствующими значениями правила первой строки (с условием NR==1), а затем сканирует последующие строки, чтобы увидеть, не превышают ли значения текущий максимум/ меньше текущего минимума, соответственно правилу (с условиемNR>1).

В конце файла (правило с условиемEND)выводит результат.

Обратите внимание , что это предполагает отсутствие пустых строк . Если они есть, вы должны заменить условие NR>1на NR>1 && NF>0. Если перед первой строкой могут быть пустые строки ,использовать

awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
     init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
                      if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
     END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat

При этом будет использоваться переменная init, чтобы проверить, была ли уже найдена не -пустая строка, и использовать содержимое первой не -пустой строки, чтобы предварительно -установить текущий максимум/минимум для обе колонки. Только если initустановлен (после этой инициализации ), (не -пустые )строки учитываются для ввода этой статистики.

Общее замечание: никогда не нужно catфайл и передавать результат в awk.

2
19.03.2021, 02:29

Попробуйте это,

awk  '{if (max == "") max=$2 ; else if ($2 > max) max=$2}END{print max}' file
awk  '{if (min == "") min=$2 ; else if ($2 < min) min=$2}END{print min}' file
1
19.03.2021, 02:29

Проблемы с кодом:

  • Вы не должны exitпока не будут обработаны все входные данные. На самом деле выход не нужен.
  • Первую строку необходимо использовать для инициализации значений max и min. Если значение поля в первой строке отрицательное, проверка, подобная min > $1, будет ложной, поскольку min еще не имеет значения (, поэтому по умолчанию используется числовое значение 0).
  • И max, и min можно было найти за один вызов awk.

Общий

Общее решение для любого количества полей (в пределах разумного )в любой строке (количество полей не обязательно должно быть постоянным )которое предполагает только, что пустое поле содержит нуль("")и который принимает все значения, которые принимает awk (обычно строки преобразуются в0)это:

awk '
{
       if(nf<NF){nf=NF};              # find the max number of fields
                                      # to print at the end
       for(i=1;i<=NF;i++){ 
                           f=$i+0;    # convert each field to a number
                           # Either initialize (if empty)
                           # or capture max and min.
                           if(max[i]==""||max[i]<f){ max[i]=f }
                           if(min[i]==""||min[i]>f){ min[i]=f }
                         }
}
END{
       for(i=1;i<=nf;i++){print i,min[i],max[i]}
}' file

В этом коротком файле (пример):

    0.1735  -23.6900
    0.2024  -23.7324
    0.2313  -23.7745
    0.2602  -23.8162  23 -12 PREC
    0.2892  -23.8574  46 -23
    0.3181  -23.8980

Вывод будет:

1 0.1735 0.3181
2 -23.898 -23.69
3 23 46
4 -23 -12
5 0 0

Для вашего файла будет напечатано:

1 0 0.4916
2 -24.1254 -23.4334
0
19.03.2021, 02:29

Это для столбца 1 (Он вычисляет среднее максимальное и минимальное значение)

sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1}  END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'

это для столбца 2

sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1}  END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'
1
19.03.2021, 02:29

Теги

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