Awk распечатывает наименьшее и наибольшее число в формате времени

Я довольно новичок в оболочке linux/bash, и у меня действительно возникают проблемы при печати двух значений (самое высокое и самое низкое) из определенного столбца в текстовом файле. Файл отформатирован так:

Geoff        Audi           2:22:35.227
Bob          Mercedes       1:24:22.338
Derek        Jaguar         1:19:77.693
Dave         Ferrari        1:08:22.921

Как вы можете видеть в последнем столбце - это время, я пытаюсь использовать awk, чтобы распечатать самое высокое и самое низкое время в столбце. Я действительно в тупик, я пытался:

awk '{print sort -n <  $NF}' timings.txt 

Однако, похоже, это ничего не сортировало, я просто получил вывод:

1
0
1
0
...

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

Мой желаемый результат будет:

Min: 1:08:22.921
Max: 2:22:35.227   

3 ответа

Решение

После уточнения вопроса: если поле времени всегда имеет одинаковое количество цифр в одном и том же месте, например h:mm:ss.ssрешение может быть существенно упрощено. А именно, нам больше не нужно преобразовывать время в секунды, чтобы сравнить его, мы можем сделать простое лексикографическое сравнение строк:

$ awk 'NR==1 {m=M=$3} {$3<m&&m=$3; $3>M&&M=$3} END {printf("min: %s\nmax: %s",m,M)}' file
min: 1:08:22.921
max: 2:22:35.227

Логика та же, что и в (предыдущем) скрипте ниже, только с использованием более простого сравнения на основе строк для значений порядка (определение мин / макс). Мы можем сделать это, так как мы знаем, что все сроки будут соответствовать одному и тому же формату, и еслиa < b(например"1:22:33" < "1:23:00") мы знаем a "меньше" чем b, (Если значения не отформатированы одинаково, то, используя только лексикографическое сравнение, мы не можем упорядочить их, например, "12:00:00" < "3:00:00".)

Итак, при первом прочтении значения (первая запись,NR==1), мы устанавливаем начальное значение min/ max для считывания времени (в 3-м поле). Для каждой записи мы проверяем, является ли текущее значение меньше текущего минимума, и если это так, мы устанавливаем новый минимум. Аналогично для макс. Вместо этого мы используем короткое замыканиеifсделать выражения короче ($3<m && m=$3эквивалентно if ($3<m) m=$3). вEND мы просто печатаем результат.


Вотобщийawkрешение, которое принимает строки времени с переменным количеством цифр для часов / минут / секунд на запись:

$ awk '{split($3,t,":"); s=t[3]+60*(t[2]+60*t[1]); if (s<min||NR==1) {min=s;min_t=$3}; if (s>max||NR==1) {max=s;max_t=$3}} END{print "min:",min_t; print "max:",max_t}' file
min: 1:22:35.227
max: 10:22:35.228

Или в более читаемой форме:

#!/usr/bin/awk -f
{
    split($3, t, ":")
    s = t[3] + 60 * (t[2] + 60 * t[1])
    if (s < min || NR == 1) {
        min = s
        min_t = $3
    }
    if (s > max || NR == 1) {
        max = s
        max_t = $3
    }
}

END {
    print "min:", min_t
    print "max:", max_t
}

Для каждой строки мы преобразуем временные компоненты (часы, минуты, секунды) из третьего поля в секунды, которые позже мы можем просто сравнить как числа. В процессе итерации мы отслеживаем текущие значения min val и max val, печатая их в END, Начальные значения для min и max взяты из первой строки (NR==1).

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

$ awk 'NR==1{min=max=$3} {min=(min<$3?min:$3); max=(max>$3?max:$3)} END{print "Min:", min ORS "Max:", max}' file
Min: 1:08:22.921
Max: 2:22:35.227

Вы не хотите запускать сортировку внутри awk (даже с правильным синтаксисом).

Попробуй это:

sed 1d timings.txt | sort -k3,3n | sed -n '1p; $p'

где

  • первый сед удалит заголовок
  • отсортировать по 3-му столбцу численно
  • второй седь напечатает первую и последнюю строку
Другие вопросы по тегам