Вопрос

У меня есть приложение, которое выглядит примерно так:

I, [2009-03-04T15:03:25.502546 #17925]  INFO -- : [8541, 931, 0, 0]
I, [2009-03-04T15:03:26.094855 #17925]  INFO -- : [8545, 6678, 0, 0]
I, [2009-03-04T15:03:26.353079 #17925]  INFO -- : [5448, 1598, 185, 0]
I, [2009-03-04T15:03:26.360148 #17925]  INFO -- : [8555, 1747, 0, 0]
I, [2009-03-04T15:03:26.367523 #17925]  INFO -- : [7630, 278, 0, 0]
I, [2009-03-04T15:03:26.375845 #17925]  INFO -- : [7640, 286, 0, 0]
I, [2009-03-04T15:03:26.562425 #17925]  INFO -- : [5721, 896, 0, 0]
I, [2009-03-04T15:03:30.951336 #17925]  INFO -- : [8551, 4752, 1587, 1]
I, [2009-03-04T15:03:30.960007 #17925]  INFO -- : [5709, 5295, 0, 0]
I, [2009-03-04T15:03:30.966612 #17925]  INFO -- : [7252, 4928, 0, 0]
I, [2009-03-04T15:03:30.974251 #17925]  INFO -- : [8561, 4883, 1, 0]
I, [2009-03-04T15:03:31.230426 #17925]  INFO -- : [8563, 3866, 250, 0]
I, [2009-03-04T15:03:31.236830 #17925]  INFO -- : [8567, 4122, 0, 0]
I, [2009-03-04T15:03:32.056901 #17925]  INFO -- : [5696, 5902, 526, 1]
I, [2009-03-04T15:03:32.086004 #17925]  INFO -- : [5805, 793, 0, 0]
I, [2009-03-04T15:03:32.110039 #17925]  INFO -- : [5786, 818, 0, 0]
I, [2009-03-04T15:03:32.131433 #17925]  INFO -- : [5777, 840, 0, 0]

Я бы хотел создать сценарий оболочки, который вычисляет среднее значение 2-го и 3-го полей в скобках (840 и 0 в последнем примере).Еще более сложный вопрос:возможно ли получить среднее значение по 3-му полю только тогда, когда последнего нет 0?

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

Это было полезно?

Решение

Здесь также публикуется ответ, который я вставил вам через IM, просто потому, что он заставляет меня попробовать StackOverflow:)

# replace $2 with the column you want to avg; 
awk '{ print $2 }' | perl -ne 'END{ printf "%.2f\n", $total/$n }; chomp; $total+= 

Здесь также публикуется ответ, который я вставил вам через IM, просто потому, что он заставляет меня попробовать StackOverflow:)

<*>; $n++' < log

Другие советы

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

cat file | sed -ne 's:^.*INFO.*\[\([0-9, ]*\)\][ \r]*$:\1:p' | awk -F ' *, *' '{ sum2 += $2 ; sum3 += $3 } END { if (NR>0) printf "avg2=%.2f, avg3=%.2f\n", sum2/NR, sum3/NR }'

Пример вывода (для ваших исходных данных):

avg2=2859.59, avg3=149.94

Конечно, вам не нужно использовать cat, он включен туда для удобства чтения и для иллюстрации того факта , что входные данные могут поступать из любого канала;если вам нужно поработать с существующим файлом, запустите sed -ne '...' file | ... напрямую.


Редактировать

Если у вас есть доступ к gawk (GNU awk), вы можете устранить необходимость в sed следующим образом:

cat file | gawk '{ if(match($0, /.*INFO.*\[([0-9, ]*)\][ \r]*$/, a)) { cnt++; split(a[1], b, / *, */); sum2+=b[2]; sum3+=b[3] } } END { if (cnt>0) printf "avg2=%.2f, avg3=%.2f\n", sum2/cnt, sum3/cnt }'

Те же замечания повторяются. cat применять.

Небольшое объяснение:

  • sed печатает только строки (-n ... :p комбинация), которые соответствуют регулярному выражению (строки, содержащие ИНФОРМАЦИЮ, за которыми следует любая комбинация цифр, пробелов и запятых в квадратных скобках в конце строки, с учетом завершающих пробелов и CR);если какая-либо такая строка совпадает, сохраните только то, что заключено в квадратные скобки (\1, соответствующий тому, что находится между \(...\) в регулярном выражении) перед печатью (:p)
    • sed выведет строки, которые выглядят следующим образом: 8541, 931, 0, 0
  • awk использует запятую , окруженную 0 или более пробелами (-F ' *, *') в качестве разделителей полей; $1 соответствует первому столбцу (например ,8541), $2 ко второму и т.д.Отсутствующие столбцы считаются значениями 0
    • в конце, awk разделяет аккумуляторы sum2 и т.д. по количеству обработанных записей, NR
  • gawk делает все одним выстрелом;сначала он проверит, соответствует ли каждая строка одному и тому же регулярному выражению, переданному в предыдущем примере sed (за исключением того, что в отличие от sed, awk не требует наличия \ в круглых скобках, ограничивающих области или интересы).Если строка совпадает, то то, что находится между круглыми скобками, заканчивается в [1], которое затем мы разделяем, используя тот же разделитель (запятую, окруженную любым количеством пробелов), и используем это для накопления.Я представил cnt вместо того, чтобы продолжать использовать NR потому что количество обработанных записей NR может быть больше фактического количества соответствующих записей (cnt) если не все строки имеют вид INFO ... [...comma-separated-numbers...], чего не было в случае с sed|awk с тех пор как sed гарантируется, что все строки будут переданы в awk были актуальны.

Используйте nawk или / usr / xpg4 / bin / awk в Solaris .

awk -F'[],]' 'END { 
  print s/NR, t/ct 
  }  
{ 
  s += $(NF-3) 
  if ($(NF-1)) {
    t += $(NF-2)
    ct++
    }
  }' infile

Использовать Python

logfile= open( "somelogfile.log", "r" )
sum2, count2= 0, 0
sum3, count3= 0, 0
for line in logfile:
    # find right-most brackets
    _, bracket, fieldtext = line.rpartition('[')
    datatext, bracket, _ = fieldtext.partition(']')
    # split fields and convert to integers
    data = map( int, datatext.split(',') )
    # compute sums and counts
    sum2 += data[1]
    count2 += 1
    if data[3] != 0:
        sum3 += data[2]
        count3 += 1
logfile.close()

print sum2, count2, float(sum2)/count2
print sum3, count3, float(sum3)/count3
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top