Использовать две команды в исходном файле awk

Я нашел два ответа на предложенная проблема:

Первый предложен @steeldriver:

    tr -s ' ' '\n' < file | pr -3t

И второй, который я нашел в другом обсуждении транспонированных матричных элементов:

awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
 NF>p { p = NF }
END {    
     for(j=1; j<=p; j++) {
          str=a[1,j]
    for(i=2; i<=NR; i++){
        str=str" "a[i,j];
    } 
    print str 

  }
 }' file
-1
27.08.2017, 22:18
3 ответа

Это однопроходное -решение:

/Nodes/         { read = 1 }
/EndNodes/      { read = 0 }

!read           { next     }

NF == 4                         { n = $1; x = $2; y = $3; z = $4 }
z > max                         { delete set; i = 1; max = z     }
x >= 0 && y == 0 && z == max    { set[i++] = n                   }

END             { for (i in set) { print set[i] } }

Переменная readопределяет, должны ли мы действовать с текущей записью или нет. Если это 1, то мы делаем.

Третий блок отбрасывает текущий ввод, если он нас не интересует, и продолжает сверху со следующей записью.

В четвертом блоке задаются четыре удобные переменные: n, x, yи z. Их приятнее читать, чем $1и т. д.

5-й блок удаляет массив set. Массив set— это набор всех номеров узлов, которые мы нашли до сих пор и которые удовлетворяют критериям. Поскольку этот блок выполняется, если мы нашли новый максимум для z, все ранее найденные узлы становятся недействительными. Также сохраняем новый максимум(max). Переменная i— это просто индекс в массиве (счетчик, в основном ). Если максимум еще не найден, то неинициализированный maxбудет считаться нулевым в тесте.

Шестой блок выполняется, когда мы нашли узел, удовлетворяющий критериям. Номер узла сохраняется в массиве set, а iувеличивается.

В конце мы перебираем массив setи выводим его содержимое.

Результат при работе под GNU awk:

20
31
32

BSD awkи mawk, работающие на OpenBSD, создают список в обратном порядке.

2
28.04.2021, 23:57

awkрешение:

получить _max _nodes.awkскрипт:

#!/bin/awk -f
BEGIN{ max=0 }
NR==FNR{                         # processing the 1st input file
    if ($4~/^[0-9]/) {           # if the 4th field is a number
        if($4+0 > max) max=$4+0  # capturing maximal number
    }
    next
}
{   # processing the 2nd input file (same file)
    if ($4~/^[0-9]/ && $2+0>=0 && $3+0==0 && $4+0==max) {
        print $1
    }
}

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

awk -f get_max_nodes.awk input.txt input.txt

Выход:

20
31
32
0
28.04.2021, 23:57

У меня недостаточно репутации, чтобы комментировать, поэтому я вынужден ответить ответом. Мой первый комментарий был бы о том, что awk — не лучший инструмент для математики с действительными числами. Это лучше для строк и целых чисел.

Другие моменты в awk :Параграф BEGIN происходит до того, как какие-либо строки будут прочитаны из вашего ввода. Параграф END происходит после прочтения всех строк.

Примечание. :awk не сохраняет и не заботится ни о чем, кроме текущей строки/записи ввода,если вы не предпримете шаги для хранения записей/полей в своем коде. Это должно произойти между BEGIN и END.

Ваш код между этими абзацами только устанавливает/сбрасывает переменные, но ничего не делает с их значениями. По сути, вы могли бы «закрепить» -1 входной файл и направить вывод в cut, чтобы добиться аналогичных результатов.

Похоже, вы намеревались проверить число в столбце 4, чтобы найти max или max1, и вывести столбец 1 только в том случае, если столбец 4 содержит этот максимум, после чего следует успешная проверка столбцов 2 и 3. Эту логику необходимо переместить перед END, если только вы не заботитесь только о последней строке файла.

Помните, что в awk каждая строка ввода (по умолчанию )сравнивается с каждым условием. Если условие истинно, выполняется действие или список действий. Вполне возможно, что несколько условий запускают действия в одной и той же строке.

Мое первое впечатление, что вам нужно -переоценить свой процесс. Определите порядок важности и примите соответствующие меры. Например, для меня первый порядок важности воздействует только на данные между двумя флагами в моем входном файле. Затем определите, могут ли действительные числа в каждом из 4 полей быть преобразованы в (или обработаны как )целые числа (или строки )без потери их значения. Сами фактические данные не нужно менять, только их представление в вашем коде. Их можно преобразовать обратно, но вероятность потери точности исходного числа высока. Наконец, выберите, нужно ли вам сохранять все/любые из этих несортированных, случайных данных для последующей обработки или выдавать немедленный вывод построчно.

Следующий мета-пример можно было бы сделать намного эффективнее... Начните с флага, чтобы вы знали, пора ли начать синтаксический анализ. Вы уже видели строку $0 ~= /Nodes/? старт=0.Вы также можете подготовиться к тому, чтобы знать, когда прекратить синтаксический анализ данных, проверив строку $0 ~= /EndNodes/, stop=0. И вам может понадобиться счетчик, если вы храните данные, count=0.

BEGIN {
   start=0
   stop=0
   count=0
   max=0
}
/EndNodes/ {
   stop=1
}
/Nodes/ {
   start=1
}
NF==4 {
   if (start==1 && stop==0) {
      count++
      column1[count]=$1
      column2[count]=substr($2,1,index($2,".")-1)
      column3[count]=substr($3,1,index($3,".")-1)
      column4[count]=substr($4,1,index($4,".")-1)
   }
}
# Now print column1 if column2 is non-negative and column3=0 and column4=max
# In the first loop through the array/list, find max
END {
   for (loop=1;loop<=count;loop++) {
      if (column4[loop]>max) {
         max=column4[loop]
      }
   }
   for (loop=1;loop<=count;loop++) {
      if (column4[loop]==max && column3[loop]==0 && column2[loop]>=0) {
         print column1[loop]
      }
   }
}

Как написано, вывод будет

20
31
32
0
28.04.2021, 23:57

Теги

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