Гуманизированные свидания с awk? - PullRequest
1 голос
/ 09 июля 2009

У меня есть этот awk-скрипт, который запускает файл и подсчитывает каждое вхождение данной даты. Формат даты в исходном файле является стандартным форматом даты, например:

Thu Mar 5 16:46:15 EST 2009
Я использую awk, чтобы отбросить день недели, время и часовой пояс, а затем выполняю мой подсчет, закачивая даты в ассоциативный массив с датами как индексы.

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

Теперь мой вывод выглядит так:

Date    Count
03/05/2009   2
03/06/2009   1
05/13/2009   7
05/22/2009  14
05/23/2009   7
05/25/2009   7
05/29/2009  11
06/02/2009  12
06/03/2009  16

Мне бы очень хотелось, чтобы в выводе было больше удобочитаемых дат, например:

Mar  5, 2009
Mar  6, 2009
May 13, 2009
May 22, 2009
May 23, 2009
May 25, 2009
May 29, 2009
Jun  2, 2009
Jun  3, 2009

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

UPDATE: Вот мое решение, включающее пример кода ghostdog74:

grep -i "E[DS]T 2009" original.txt | awk '{printf "%s %2.d, %s\r\n",$2,$3,$6}' >dates.txt #outputs dates for counting
date -f dates.txt +'%Y %m %d' | awk ' #reformat dates as YYYYMMDD for future sort
  {++total[$0]} #pump dates into associative array
  END { 
    for (item in total) printf "%s\t%s\r\n", item, total[item] #output dates as yyyy mm dd with counts
  }' | sort -t \t | awk ' #send to sort, then to cleanup
  BEGIN {printf "%s\t%s\r\n","Date","Count"}
  {t=$1" "$2" "$3" 0 0 0" #cleanup using example by ghostdog74
   printf "%s\t%2.d\r\n",strftime("%b %d, %Y",mktime(t)),$4
  }'
rm dates.txt

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

Ответы [ 5 ]

3 голосов
/ 10 июля 2009

Используйте стандарт сортировки и даты в awk, чтобы значительно упростить сценарий

Дата будет принимать входные данные от stdin, поэтому вы можете исключить один канал для awk и временный файл. Вы также можете удалить канал до sort, используя сортировку массива awk, и, как следствие, удалить другой канал для awk. Кроме того, нет необходимости в сопроцессе.

Этот сценарий использует date для преобразования названия месяца, которое предположительно продолжит работать на других языках (однако, игнорируя проблемы с часовым поясом и порядком месяца / дня).

Конечный результат выглядит как «grep | date | awk». Я разбил его на отдельные строки для удобства чтения (было бы примерно вдвое меньше, если бы комментарии были удалены):

grep -i "E[DS]T 2009" original.txt | 
date -f - +'%Y %m %d' | #reformat dates as YYYYMMDD for future sort
awk ' 
BEGIN { printf "%s\t%s\r\n","Date","Count" }

{ ++total[$0] #pump dates into associative array }

END {
    idx=1
    for (item in total) {
        d[idx]=item;idx++ # copy the array indices into the contents of a new array
    }
    c=asort(d) # sort the contents of the copy
    for (i=1;i<=c;i++) { # use the contents of the copy to index into the original
        printf "%s\t%2.d\r\n",strftime("%b %e, %Y",mktime(d[i]" 0 0 0")),total[d[i]]
    }
}'
3 голосов
/ 09 июля 2009

Я становлюсь раздражительным, когда вижу, что кто-то использует grep и awk (и sed, cut, ...) в конвейере. Awk может полностью справиться с работой многих утилит.

Вот способ очистить ваш обновленный код для запуска в одном экземпляре awk (ну, gawk) и использовать сортировку в качестве совместного процесса:

gawk '
    BEGIN {
        IGNORECASE = 1
    }
    function mon2num(mon) {
        return(((index("JanFebMarAprMayJunJulAugSepOctNovDec", mon)-1)/3)+1)
    }
    / E[DS]T [[:digit:]][[:digit:]][[:digit:]][[:digit:]]/ {
        month=$2
        day=$3
        year=$6
        date=sprintf("%4d%02d%02d", year, mon2num(month), day)
        total[date]++
        human[date] = sprintf("%3s %2d, %4d", month, day, year)
    }
    END {
        sort_coprocess = "sort"
        for (date in total) {
            print date |& sort_coprocess
        }
        close(sort_coprocess, "to")
        print "Date\tCount"
        while ((sort_coprocess |& getline date) > 0) {
            print human[date] "\t" total[date]
        }
        close(sort_coprocess)
    }
' original.txt
1 голос
/ 09 июля 2009

, если вы используете gawk

awk 'BEGIN{
    s="03/05/2009"
    m=split(s,date,"/")
    t=date[3]" "date[2]" "date[1]" 0 0 0"
    print strftime("%b %d",mktime(t))
}'

Выше приведен только пример, так как вы не показали свой реальный код и не можете включить его в свой код.

1 голос
/ 09 июля 2009

Почему вы не добавляете свою awk-дату к исходной дате? Это дает сортируемый ключ, но удобочитаем для человека.

(Примечание: чтобы отсортировать правильно, вы должны сделать это ггггммдд)

При необходимости вырезать можно удалить предварительно столбец.

0 голосов
/ 09 июля 2009

Gawk имеет strftime (). Вы также можете вызвать команду date для их форматирования ( man ). Linux Forums приводит несколько примеров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...