Home > Back-end >  Bash - Sort File Based on 2 Columns : HH:MM:SS AM/PM
Bash - Sort File Based on 2 Columns : HH:MM:SS AM/PM

Time:11-16

Trying to sort lines in a file. The column1 is HH:MM:SS format and col2 is AM/PM. Need to arrange lines from AM to PM firstly and then progressive time.

Current :

11:36:48 AM col3 ...
11:32:00 AM col3 ...
03:18:54 PM col3 ...
02:26:40 PM col3 ...
01:51:56 PM col3 ...
12:55:58 PM col3 ...
11:58:48 AM col3 ...
09:38:41 AM col3 ...

Final:

09:38:41 AM col3 ...
11:32:00 AM col3 ...
11:36:48 AM col3 ...
11:58:48 AM col3 ...
12:55:58 PM col3 ...
01:51:56 PM col3 ...
02:26:40 PM col3 ...
03:18:54 PM col3 ...

Thanks

CodePudding user response:

All you have to do is get the AM lines with grep, then use sort on the output. After doing that then you can do the same for the PM lines.

cp "my_file" "backup_file" #Backup old file before overwriting
grep '^[0-9:]* AM' "backup_file" | sort > "my_file"
grep '^[0-9:]* PM' "backup_file" | sort >> "my_file"

Its important to backup your file before using > operation since that will completely overwrite your file.

CodePudding user response:

A Schwartzian transform:

while read -ra fields; do
    printf '%s\t%s\n' "$(date -d "${fields[*]:0:2}" ' %s')" "${fields[*]}"
done < input \
| sort -n \
| cut -f 2-

outputs

09:38:41 AM col3 ...
11:32:00 AM col3 ...
11:36:48 AM col3 ...
11:58:48 AM col3 ...
12:55:58 PM col3 ...
01:51:56 PM col3 ...
02:26:40 PM col3 ...
03:18:54 PM col3 ...

The while loop calculates the epoch time for each timestamp and adds it to the output stream. Then it gets sorted by the numeric time. Then that field is removed.

Doing this in bash may be slower than doing it in, say, perl:

perl -MTime::Piece -lane '
        push @lines, [@F];
    } END {
        print join "\n",
              map {"@{$_->[1]}"}
              sort {$a->[0] <=> $b->[0]}
              map {[Time::Piece->strptime("$_->[0] $_->[1]", "%T %p")->epoch, $_]}
              @lines;
' input
  • Related