0

I want to sort the following rows of text to a particular order. The sort commands I am using is dropping the space and bundling all the lines together without the space separation and putting them in alphabetical order. Each block has 8 rows of line data each.

session:cabSessionID:052FPBP6Q6X2XGERWHBT
cabLoginID:053XCDTF8D4J6PD3BG8P
loginName:jack
userAgent:Mozilla/5.0
sessionStartTime:2018-10-01T01:04:10.899Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:42358792
usedJSHeapSize:36482584

session:cabSessionID:052FPBP6Q6X2XGERWHJE
cabLoginID:053XCDTF8D4J6PD3BG8P
loginName:jack
userAgent:Mozilla/5.0
sessionStartTime:2018-10-01T01:16:41.558Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:177754040
usedJSHeapSize:44842320

memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:45252608
usedJSHeapSize:24555080
session:cabSessionID:055S75T4QC8JYC4Q0456
cabLoginID:053XCDTF8D4J6PD3BG8P
loginName:frank
userAgent:Mozilla/5.0
sessionStartTime:2018-10-23T19:11:11.871Z

I want the end result to be like this:

loginName:jack
cabLoginID:053XCDTF8D4J6PD3BG8P
session:cabSessionID:052FPBP6Q6X2XGERWHBT
userAgent:Mozilla/5.0
sessionStartTime:2018-10-01T01:04:10.899Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:42358792
usedJSHeapSize:36482584

loginName:jack
cabLoginID:053XCDTF8D4J6PD3BG8P
session:cabSessionID:052FPBP6Q6X2XGERWHJE
userAgent:Mozilla/5.0
sessionStartTime:2018-10-01T01:16:41.558Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:177754040
usedJSHeapSize:44842320

loginName:fred
cabLoginID:053XCDTF8D4J6PD3BG8P
session:cabSessionID:055S75T4QC8JYC4Q0456
userAgent:Mozilla/5.0
sessionStartTime:2018-10-23T19:11:11.871Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:45252608
usedJSHeapSize:24555080

  • Hi Jeff, each block needs to be sort in the following order: loginName, cabLoginID, session, userAgent, sessionStartTime, memoryInfo, totalJSHeapSize, usedJSHeapSize. I don't need to reorder the blocks itself, it can stay in the same order as it is – Kam Oct 24 '18 at 20:06
1

Since you want to hard-code the "sorting", have awk compile the data for each block in an associative array, then print that array out in the order you want:

scriptfile.awk

BEGIN {
  FS=":"
}

/./ {
  values[$1]=$0
}

/^$/ {
  print values["loginName"]
  print values["cabLoginID"]
  print values["session"]
  print values["userAgent"]
  print values["sessionStartTime"]
  print values["memoryInfo"]
  print values["totalJSHeapSize"]
  print values["usedJSHeapSize"]
  print ""
  delete values
}

END {
  print values["loginName"]
  print values["cabLoginID"]
  print values["session"]
  print values["userAgent"]
  print values["sessionStartTime"]
  print values["memoryInfo"]
  print values["totalJSHeapSize"]
  print values["usedJSHeapSize"]
}

Then run:

awk -f scriptfile.awk < input

As an alternative, if you don't care what order the block lines are in, but do want them still to be consistently ordered, and you have GNU awk,

gnuscript.awk

BEGIN {
  FS=":"
  PROCINFO["sorted_in"]="@val_str_asc";
}

/./ {
  values[$1]=$0
}

/^$/ {
  asort(values)
  for (element in values)
    print values[element]
  print ""
  delete values
}

END {
  asort(values)
  for (element in values)
    print values[element]
}

The above script prints the lines of each block in alphabetical order:

cabLoginID:053XCDTF8D4J6PD3BG8P
loginName:jack
memoryInfo:jsHeapSizeLimit:2217857988
session:cabSessionID:052FPBP6Q6X2XGERWHBT
sessionStartTime:2018-10-01T01:04:10.899Z
totalJSHeapSize:42358792
usedJSHeapSize:36482584
userAgent:Mozilla/5.0
...
  • would it be an easier "one liner" if the requirement of sorting it a particular way is not required? As long as the sorting is in the same order again and again. Thanks for the response by the way! – Kam Oct 24 '18 at 20:20
  • 1
    Will this awk script work with the times? The times contain colons. I don't think the entire time will be captured. – Lewis M Oct 24 '18 at 20:26
  • 1
    it broke on lines that had more than one semicolon. For example on session, it displays as session:cabSessionID instead of session:cabSessionID:052FPBP6Q6X2XGERWHBT – Kam Oct 24 '18 at 20:31
  • 1
    Ah, thanks, don! I was just about to update the post, but you beat me to it. Much simpler, too -- thank you! I'll work on a further simplification regarding Kam's direction of printing block-lines in the same order. – Jeff Schaller Oct 24 '18 at 21:25
  • @Kam, I've added a GNU awk variation that's simpler, by relying on GNU awk's ability to sort; here I've chosen "ascending string", but you can also define your own sort function. – Jeff Schaller Oct 24 '18 at 21:33
1

You could use Perl in paragraph mode, with a custom sort order defined using a hash e.g.

perl -00 -F'\n' -ne '
our %rank; 
BEGIN {
  %rank = (
    loginName => 1,
    cabLoginID => 2,
    session => 3,
    userAgent => 4,
    sessionStartTime => 5,
    memoryInfo => 6,
    totalJSHeapSize => 7,
    usedJSHeapSize => 8
  );
}

%h = ();
map { ($k,$v) = split(/:/, $_, 2); $h{$k} = $v } @F;
for $k (sort { $rank{$a} <=> $rank{$b} } keys %h) { print "$k:$h{$k}\n" };
print "\n";
' file
1

If you want to sort a block of lines the same way over and over, I do not think there is a simple one-liner for that.

Since I'm concerned with the awk not catching all of the strings because of the colons in the times, I wrote up this quick little shell script. This actually sorts them by blocks. The order you have it in the blocks is determined by the printf. Update that to meet your needs.

#!/bin/bash

declare -A arr

(
  while read l; do
    if [[ "" == "${l}" ]]; then
      printf "loginName:%s~cabLoginID:%s~session:%s~userAgent:%s~sessionStartTime:%s~memoryInfo:%s~totalJSHeapSize:%s~usedJSHeapSize:%s~\n" ${arr[loginName]} ${arr[cabLoginID]} ${arr[session]} ${arr[userAgent]} ${arr[sessionStartTime]} ${arr[memoryInfo]} ${arr[totalJSHeapSize]} ${arr[usedJSHeapSize]}
      unset arr
      declare -A arr
      continue
    fi
    k=${l%%:*}
    v=${l#*:}
    arr[${k}]=${v}
  done
  printf "loginName:%s~cabLoginID:%s~session:%s~userAgent:%s~sessionStartTime:%s~memoryInfo:%s~totalJSHeapSize:%s~usedJSHeapSize:%s~\n" ${arr[loginName]} ${arr[cabLoginID]} ${arr[session]} ${arr[userAgent]} ${arr[sessionStartTime]} ${arr[memoryInfo]} ${arr[totalJSHeapSize]} ${arr[usedJSHeapSize]}
) | sort | tr '~' '\n'

exit 0
  • Thanks Lewis for coming back. I took your code and saved it on a file called scriptfile2 with a .sh extension. For me to initiate the codes against the file that has this information, is it as easy as: ./scriptfile2.sh < FinalResult.txt – Kam Oct 24 '18 at 20:40
  • If FinalResult.txt is the file containing your data, yes. – Lewis M Oct 26 '18 at 12:19
0

Try also

awk '
BEGIN   {for (n=split("loginName cabLoginID session userAgent sessionStartTime memoryInfo totalJSHeapSize usedJSHeapSize", T); n; n--) FLSQ[T[n]] = n
        }

        {for (i=1; i<=NF; i++)  {n = split ($i, T, ":")
                                 OUT[FLSQ[T[1]]] = $i
                                }
         for (i=1; i<=NF; i++) $i = OUT[i]
         split ("", OUT)
        }
1
' RS="" ORS="\n\n" FS="\n" OFS="\n"  file
loginName:jack
cabLoginID:053XCDTF8D4J6PD3BG8P
session:cabSessionID:052FPBP6Q6X2XGERWHBT
userAgent:Mozilla/5.0
sessionStartTime:2018-10-01T01:04:10.899Z
memoryInfo:jsHeapSizeLimit:2217857988
totalJSHeapSize:42358792
usedJSHeapSize:36482584

.
.
.

In the BEGIN section, it defines the field sequence in each record's output by assigning each field label an ascending number. When operating on multiline records, having split the label into the T array, it fills the OUT array with the entire field, indexed by the label's number. Last action before printing the record is to rebuild the entire $0 (= record). All field and record separators have to be adapted to the multiline record layout.

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.