Find the durations and their average between the dataset in an interval in shell script

大憨熊 提交于 2020-01-16 03:50:09

问题


This is related to my older question Find the durations and their maximum between the dataset in an interval in shell script

I have a dataset as:

ifile.txt
2
3
2
3
2
20
2
0
2
0
0
2
1
2
5
6
7
0
3
0
3
4
5

I would like to find out different duration and their average between the 0 values in 6 values interval.

My desire output is:

ofile.txt
6 5.33
1 2
1 2
1 2
5 4.2
1 3
3 4

Where

6 is the number of counts until next 0 within 6 values (i.e. 2,3,2,3,2,20) and 5.33 is the average value among them;
1 is the number of counts until next 0 within next 6 values (i.e. 2,0,2,0,0,2) and 2 is the average;
Next 1 and 2 are within same 6 values;
5 is the number of counts until next 0 within next 6 values (i.e. 1,2,5,6,7,0) and 4.2 is the average among them;
And so on

As per the answer to my previous question, I was trying with this:

    awk '
$0!=0{
  count++
  sum=sum+$0
  found=""
}
$0==0{
  print count,max
  count=max=0
  next
}
FNR%6==0{
  print count,max
  count=max=0
  found=1
}
END{
  if(!found){
      print count,max
  }
}
'  Input_file | awk '!/^ /' | awk '$1 != 0'

回答1:


EDIT3: One more try since 2nd set of 6 lines have 2 0 2 0 0 2 so its output should be 1 2, 1 2, 0 0,1 2 if this is the case(which I believe ideally should be) then try following.

awk '
{
  occur++
}
{
  count=$0!=0?++count:count
  sum+=$0
}
$0==0 || occur==6{
  printf("%d %0.2f\n",count,count?sum/count:prev)
  prev=count?sum/count:0
  prev_count=count
  count=sum=prev=prev_count=""
  if(occur==6){
    occur=""
  }
}
END{
  if(occur){
      printf("%d %0.2f\n",count?count:prev_count,count?sum/count:prev)
  }
}
'  Input_file | awk '$1 != 0'

Output will be as follows:

6 5.33
1 2.00
1 2.00
1 2.00
5 4.20
1 3.00
3 4.00


EDITs below may help in similar kind of problems which are bit different from this actual problem, so keeping them here in post.

EDIT2: In case you don't want to RESET count whenever a zero occurs in Input_file then try following. This will continuously look for only 6 lines and will NOT RESET its count.

awk '
{
  occur++
}
$0!=0{
  count++
  sum+=$0
  found=prev_count=prev=""
}
$0==0 && occur!=6{
  printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)
  prev=count?sum/count:0
  prev_count=count
  count=sum=""
  found=1
  next
}
occur==6{
  printf("%d,%0.2f\n",count,count?sum/count:prev)
  prev=count?sum/count:0
  prev_count=count
  count=sum=occur=""
  found=1
}
END{
  if(!found){
      printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)
  }
}
'  Input_file


EDIT1: Could you please try following, tested and written with provided samples only.

awk '
{
  occur++
}
$0!=0{
  count++
  sum+=$0
  found=prev_count=prev=""
}
$0==0{
  printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)
  prev=count?sum/count:0
  prev_count=count
  count=sum=occur=""
  found=1
  next
}
occur==6{
  printf("%d,%0.2f\n",count,count?sum/count:prev)
  prev=count?sum/count:0
  prev_count=count
  count=sum=occur=""
  found=1
}
END{
  if(!found){
      printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)
  }
}
'  Input_file

What does code take care of:

  • It takes care of logic where if any continuous 2 lines are having 0 value then it will print previous count and average values for that line.
  • This will also take care of edge cases like:

    a- In case a line is either NOT ending with a 0 it will check if some values are there to print by found flag I created.

    b- In case of any Input_file's last line is NOT divided by 6 then also this case will be covered by END block's logic of checking it by found flag.

Explanation: Adding a detailed explanation for above code.

awk '                                                                      ##Starting awk program from here.
{
  occur++
}
$0!=0{                                                                     ##Checking condition if a line is NOT having zero value then do following.
  count++                                                                  ##Increment variable count with 1 each time it comes here.
  sum+=$0                                                                  ##Creating variable sum and keep adding current line value in it.
  found=prev_count=prev=""                                                 ##Nullifying variables found, prev_count, prev here.
}                                                                          ##Closing BLOCK for condition $0!=0 here.
$0==0{                                                                     ##Checking condition if a line is having value zero then do following.
  printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)         ##Printing count and count/sum here, making sure later is NOT getting divided by 0 too.
  prev=count?sum/count:0                                                   ##Creating variable prev which will be sum/count or zero in case count variable is NULL.
  prev_count=count                                                         ##Creating variable prev_count whose value is count.
  count=sum=occur=""                                                       ##Nullify variables count and sum here.
  found=1                                                                  ##Setting value 1 to variable found here.
  next                                                                     ##next will skip all further statements from here.
}                                                                          ##Closing BLOCK for condition $0==0 here.
occur==6{                                                                  ##Checking if current line is fully divided with 6 then do following.
  printf("%d,%0.2f\n",count,count?sum/count:prev)                          ##Printing count and count/sum here, making sure later is NOT getting divided by 0 too.
  prev=count?sum/count:0                                                   ##Creating variable prev which will be sum/count or zero in case count variable is NULL.
  prev_count=count                                                         ##Creating variable prev_count whose value is count.
  count=sum=occur=""                                                       ##Nullifying variables count and sum here.
  found=1                                                                  ##Setting value 1 to variable found here.
}                                                                          ##Closing BLOCK for condition FNR%6==0 here.
END{                                                                       ##Starting END block for this awk program here.
  if(!found){                                                              ##Checking condition if variable found is NULL then do following.
      printf("%d,%0.2f\n",count?count:prev_count,count?sum/count:prev)     ##Printing count and count/sum here, making sure later is NOT getting divided by 0 too.
  }
}
'  Input_file                                                                ##Mentioning Input_file name here.



回答2:


Another which didn't turn out quite the one-liner I was going for:

$ tail -n +2 file |        # strip header with tail to not disturb NR
awk ' 
{ 
    s+=$0                  # sum them up
    c++                    # keep count
}
$0==0 || NR%6==0 {         # act if zero or every 6th record
    if($0==0)              # remove zero effect on c
        c--
    if(s>0)                # avoid division by zero
        print c,s/c        # output
    s=c=0                  # rinse and repeat
}
END {                      # the end-game if NR%6!=0
    if($0==0)
        c--
    if(s>0)
        print c,s/c
}' 

Output:

6 5.33333
1 2
1 2
1 2
5 4.2
1 3
3 4

The tail removes the header in the file before feeding the data to awk, the idea is that the header won't show in the NR. If you don't have a header, just awk ... file.



来源:https://stackoverflow.com/questions/59621874/find-the-durations-and-their-average-between-the-dataset-in-an-interval-in-shell

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!