1

I'm looking for "sort -z" (supported only in GNU) equivalent in Solaris, so I could have multi-line "block" support. I want to sort some text by chronological order ( date then time ), and that the sort will not break the text blocks in the process.

Example, I have:

2020-05-15:02:00:00:000 INFO[LF]
2020-05-15:02:00:02:000 INFO[LF]
[HT]some extra data as second line[LF]
[HT]2020-05-15:02:00:01:000 INFO[LF]
[HT]some extra data as second line[LF]
[HT]some extra data as third line[LF]
2020-05-15:02:00:04:000 INFO[LF]
2020-05-15:02:00:03:000 INFO[LF]
  • [HT] is horizontal tab key and [LF] is \n

and I wish it to be sorted into

2020-05-15:02:00:00:000 INFO[LF]
2020-05-15:02:00:01:000 INFO[LF]
[HT]extra data as second line[LF]
[HT]some extra data as third line[LF]
2020-05-15:02:00:02:000 INFO[LF]
[HT]extra data as second line[LF]
2020-05-15:02:00:03:000 INFO[LF]
2020-05-15:02:00:04:000 INFO[LF]

on Centos/ubuntu (GNU) I manage to do that with: sort -zt : -k2,2 -k3,3n -k4,4n -k5,5n -k6,6n ( although not sure the milisec is being sorted ok ).

Please note:

  1. I can't use msort - awk / sed / perl one-liner solutions are welcome.
  2. each line is ending with LF, multi-line or not.
  3. Multi lines ( 2nd line including and ahead ) starts with HF "tab" char.

Thanks :-)

6
  • 1
    GNU sort -z is to sort NUL-delimited records. Where are the NULs in your input? Commented May 24, 2020 at 16:50
  • 1
    What release of Solaris are you using? Do you have GNU sort available as gsort?
    – Kusalananda
    Commented May 24, 2020 at 16:50
  • 1. Oracle Solaris 11.4 2. just checked my log, it contains LF symbol at the end of each line including the multi-lines. "sort -z" do work on that log while I use centos.
    – gps3dx
    Commented May 24, 2020 at 17:08
  • Just updated post: there's HF at the start of each multi-line ( from 2nd line included and above ). There's LF at the end of each line ( multi-line or not ).
    – gps3dx
    Commented May 24, 2020 at 17:46
  • OK I agree, the -"z" switch is massing up the sort... so I can't even use it on GNU.
    – gps3dx
    Commented May 24, 2020 at 18:14

2 Answers 2

1

With perl:

perl -0777 -ne 'print sort /^\d.*\n(?:\D.*\n)*/gm' your-file

That loads the whole file in memory (slurp mode with -0777 -p), extracts the blocks based on that regexps (line starting (^) with a digit (\d) following 0 or more (*) lines starting with a non-digit (\D)) and prints them after sorting.

12
  • That seems almost there to what I need... its wonderful - thanks. how can I control how the sort is being done, per column with ":" being the delimiter ? I what it chronologically, so date before time, H before M etc...
    – gps3dx
    Commented May 24, 2020 at 20:43
  • NM what I just wrote... issue is AFAIK that I need to zcat output of multiple text file before I pass it to perl... issue is that sort is working per file one by one, instead of sorting all the text from all the files togather. is there a ways to perl directly from multiple gz compressed text files ?
    – gps3dx
    Commented May 24, 2020 at 20:49
  • @gps3dx, with that date format, to sort chronologically, you just need to sort lexically. zcat ./*.gz... | perl ... to process the concatenation of compressed files as a whole. Commented May 25, 2020 at 5:23
  • Thanks for the reply. I already run it like you stated, but the output is sorted 1 file after the other chronologically - i.e not as a whole 1 big /large text. i.e I do 'zcat *.gz | perl...' like you told me... output is: 2020-05-15:00:00:00:000 2020-05-15:01:00:00:000 2020-05-15:02:00:00:000 ... 2020-05-15:23:59:00:000 2020-05-15:00:00:00:000 2020-05-15:01:00:00:000 2020-05-15:02:00:00:000
    – gps3dx
    Commented May 25, 2020 at 6:48
  • @gps3dx, if you want to sort them separately, you can do: perl ... 'zcat file1.gz|' 'zcat file2.gz|' ... or for f in ./*.gz; do zcat "$f" | perl ...; done Commented May 25, 2020 at 6:51
0

To sort null-separated records, if there's a character that's guaranteed not to appear in your data, you can use tr to swap it with null bytes. However that won't help you directly since your data is separated by newlines, and even GNU sort doesn't have an option to treat only certain newlines as separators. You need to translate newline-tab sequences to something that doesn't contain a newline, then sort, then undo the original translation.

Assuming that your data doesn't contain tabs other than a single tab at the beginning of some lines, the translation can be to remove newlines before tabs, and add them back after sorting.

awk '/^\t/ {line = line $0; next}
     {print line; line = $0}
     END {print line}' |
sort |
awk '{gsub(/\t/, "\n\t"); print}'

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .