سؤال

لدي الذي يبدو مثل هذا:

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]

أرغب في إنشاء برنامج نصي لـ Shell يحسب متوسط ​​الحقلين الثاني والثالث بين قوسين (840 و 0 في المثال الأخير).سؤال أصعب:هل من الممكن الحصول على متوسط ​​الحقل الثالث فقط عندما لا يكون الحقل الأخير كذلك 0?

أعلم أنه يمكنني استخدامها Ruby أو لغة أخرى لإنشاء برنامج نصي، ولكنني أرغب في القيام بذلك بها Bash.أي اقتراحات جيدة بشأن الموارد أو تلميحات حول كيفية إنشاء مثل هذا البرنامج النصي من شأنها أن تساعد.

هل كانت مفيدة؟

المحلول

نشر الرد الذي ألصقته لك عبر المراسلة الفورية هنا أيضًا، فقط لأنه يجعلني أجرب StackOverflow :)

# replace $2 with the column you want to avg; 
awk '{ print $2 }' | perl -ne 'END{ printf "%.2f\n", $total/$n }; chomp; $total+= $_; $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 تركيبة) التي تطابق التعبير العادي (الأسطر التي تحتوي على INFO متبوعة بأي مجموعة من الأرقام والمسافات والفواصل بين قوسين مربعين في نهاية السطر، مما يسمح بمسافات زائدة و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 كانت ذات صلة.

يستخدم ناوك أو /usr/xpg4/bin/awk على سولاريس.

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

استخدم بايثون

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