4

I have a huge text file, each line contains value or text pattern.

How can I find average or at least sum values between each pattern?

Are there any awk/sed or maybe perl solutions?

Example:

pattern1
200
300
pattern2
200
100
200
pattern3
pattern4

Expected output:

pattern1
250
pattern2
166
pattern3
pattern4
  • 2
    awk and perl would be good languages to use to solve this. Not sed, as it doesn't have any facility for arithmetic. What attempts have you made to solve this, and where are you stuck? – glenn jackman Oct 30 '19 at 14:59
  • Will you have values after the last pattern? – glenn jackman Oct 30 '19 at 15:09
  • No values after last pattern – 干猕猴桃 Oct 30 '19 at 15:11
4

Awk approach:

awk '/pattern/{ if (cnt) { printf "%d\n", sum/cnt; sum=cnt=0 } print }
     /^[0-9]+$/{ sum += $1; cnt++ }' file

The output:

pattern1
250
pattern2
166
pattern3
pattern4
  • 1
    If there are numbers after the last pattern, you'll need to do something in an END block. – glenn jackman Oct 30 '19 at 15:03
  • @glennjackman, they won't show up anyway, will be ignored in that case – RomanPerekhrest Oct 30 '19 at 15:04
  • Many thanks to @RomanPerekhrest , it works! I just only add /pattern1|pattern2/... because have several quite different patterns – 干猕猴桃 Oct 30 '19 at 15:09
  • @干猕猴桃, how those patterns are actually look like? – RomanPerekhrest Oct 30 '19 at 15:10
  • 1
    It might actually make more sense to test for all numeric lines and next there given the OP says in a comment I just only add /pattern1|pattern2/... because have several quite different patterns to avoid all those different "pattenrs" (ugh!) BUT only the OP will know for sure... – Ed Morton Oct 31 '19 at 12:18
0

Using the Gnu tools sed n dc we can do this:

$ sed -re '
    /^[0-9]+$/,/pattern/!b
    /^[0-9]+$/{H;d;}
    x;y/\n/ /
    s#.*#dc -e "0dsn&[+ln1+snz1<+]s+l+xln/p"#ep
    z;x
' file

Results:

pattern1
250
pattern2
166
pattern3
pattern4

Assuming the trailing line cannot be a number. Also assuming no negative nums.

We setup a range in sed to look for lines comprising only digits to pattern. Outside this all are printed as is. The numbers are appended in hold nd then on tge the pattern line the average is computed using the s///e command of gnu sed utilizing the dc utility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.