Home > front end >  sorting by inconsistently formatted elapsed time field ( k8s events by actual time since event )
sorting by inconsistently formatted elapsed time field ( k8s events by actual time since event )

Time:12-14

I find myself frequently looking to see if something has stopped happening. To do this, it helps to see events in chronological order...

The solutions in here do not reformat the field, and the sorting appears to be happening in character sort order, not time/numeric...or maybe on some other field...

The solution I have working -

kubectl get events |
  sed -E '/^[6789][0-9]s/{h; s/^(.).*/\1/; y/6789/0123/; s/^(.)/01m\1/;
                          x; s/^.(.*)/\1/; H;
                          x; s/\n//; };
          s/^10([0-9]s)/01m4\1/; s/^11([0-9]s)/01m5\1/; s/^([0-9]s)/00m0\1/; s/^([0-9] s)/00m\1/;
          s/^([0-9]m)/0\1/; s/^([0-9] m)([0-9]s)/\10\2/;
          s/^L/_L/;' | sort -r

...this seems a bit like overkill to me.

The whitespace-delimited left-justified fields have no leading zeroes, report only seconds up to 2m as [0-9] s, then report as [0-9] m[0-9] s up to 5m, after which it seems to report only [0-9] m.

Anyone have a short, maybe even simple-ish, easier to read solution that works?
No preference of tool (sed, awk, perl, native bash, etc), as long as it works and is likely to be already installed anywhere I need to work.

It's not a high priority, but seemed like a fun little challenge I thought I'd share.

$: cat sample
LAST ...
2m36s ...
2m9s ...
28s ...
2m22s ...
2m6s ...
46m ...
7s ...
45m ...
3m9s ...
31m ...
16m ...
75s ...
74s ...
67s ...
46m ...
63s ...
2m15s ...
119s ...
16m ...
75s ...
74s ...
69s ...
46m ...
31m ...
16m ...
75s ...
62s ...

$: sed -E '/^[6789][0-9]s/{h; s/^(.).*/\1/; y/6789/0123/; s/^(.)/01m\1/;
                           x; s/^.(.*)/\1/; H;
                           x; s/\n//; };
           s/^10([0-9]s)/01m4\1/; s/^11([0-9]s)/01m5\1/; s/^([0-9]s)/00m0\1/; s/^([0-9] s)/00m\1/;
           s/^([0-9]m)/0\1/; s/^([0-9] m)([0-9]s)/\10\2/;
           s/^L/_L/;' sample | sort -r
_LAST ...
46m ...
46m ...
46m ...
45m ...
31m ...
31m ...
16m ...
16m ...
16m ...
03m09s ...
02m36s ...
02m22s ...
02m15s ...
02m09s ...
02m06s ...
01m59s ...
01m15s ...
01m15s ...
01m15s ...
01m14s ...
01m14s ...
01m09s ...
01m07s ...
01m03s ...
01m02s ...
00m28s ...
00m07s ...

CodePudding user response:

I would harness GNU AWK for this task following way, let file.txt content be

2m36s ...
2m9s ...
28s ...
2m22s ...
2m6s ...
46m ...
7s ...
45m ...
3m9s ...
31m ...
16m ...
75s ...
74s ...
67s ...
46m ...
63s ...
2m15s ...
119s ...
16m ...
75s ...
74s ...
69s ...
46m ...
31m ...
16m ...
75s ...
62s ...

then

awk '$1!~/m/{$1="0m" $1}{split($1,arr,/m/);$1=arr[1]*60 arr[2];print}' file.txt

gives output

156 ...
129 ...
28 ...
142 ...
126 ...
2760 ...
7 ...
2700 ...
189 ...
1860 ...
960 ...
75 ...
74 ...
67 ...
2760 ...
63 ...
135 ...
119 ...
960 ...
75 ...
74 ...
69 ...
2760 ...
1860 ...
960 ...
75 ...
62 ...

Explanation: if there is not m in 1st field I prepend 0m, then I use split function at m characters, then I compute value: I multiply by 60 what is before m to convert to seconds and add what is after to get total in seconds, for rows where there is not seconds part, seconds part is empty string which is turned into zero when used in arithmetics. This output might be then sorted numerically that is

awk '$1!~/m/{$1="0m" $1}{split($1,arr,/m/);$1=arr[1]*60 arr[2];print}' file.txt | sort -n

which gives output

7 ...
28 ...
62 ...
63 ...
67 ...
69 ...
74 ...
74 ...
75 ...
75 ...
75 ...
119 ...
126 ...
129 ...
135 ...
142 ...
156 ...
189 ...
960 ...
960 ...
960 ...
1860 ...
1860 ...
2700 ...
2760 ...
2760 ...
2760 ...

(tested in GNU Awk 5.0.1 and sort (GNU coreutils) 8.30)

CodePudding user response:

If all possible time formats are shown in the example, this might work. It shows the file, the output and the final sort, pasted together for clarity.

It looks for m, multiplies by 60 and adds any existing seconds. If no m is found it simply prints the seconds.

$ paste sample <(awk '/m/{split($1,ar,"m"); print ar[1] * 60   ar[2]} 
                 !/m/{print $1 * 1}' sample) | sort -nk 3
7s ...  7
28s ... 28
62s ... 62
63s ... 63
67s ... 67
69s ... 69
74s ... 74
74s ... 74
75s ... 75
75s ... 75
75s ... 75
119s ...    119
2m6s ...    126
2m9s ...    129
2m15s ...   135
2m22s ...   142
2m36s ...   156
3m9s ...    189
16m ... 960
16m ... 960
16m ... 960
31m ... 1860
31m ... 1860
45m ... 2700
46m ... 2760
46m ... 2760
46m ... 2760
  • Related