Sorting pairs of lines based on a single field in one of those lines Sorting pairs of lines based on a single field in one of those lines shell shell

Sorting pairs of lines based on a single field in one of those lines


Transform your data into an easily-sorted format, then sort it back. So:

to_one_line_per_record() {  local inf_line= line=  while read -r line; do    if [[ $line = "#"* ]]; then      inf_line=$line    else      printf '%s\n' "${inf_line},$line"    fi  done}from_one_line_per_record() {  local inf_f1 inf_f2 url  while IFS=, read -r inf_f1 inf_f2 url; do    printf '%s,%s\n%s\n' "$inf_f1" "$inf_f2" "$url"  done}to_one_line_from_record | sort -t, -k2,2 | from_one_line_per_record

With your given input, the output of to_one_line_per_record is:

#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBC,http://AnotherStreamUrl.m3u8#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HD,http://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discovery,http://DisStreamUrl.m3u8

Passing that through sort -t, -k2,2, the output becomes:

#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HD,http://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discovery,http://DisStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBC,http://AnotherStreamUrl.m3u8

And passing that through from_one_line_per_record, it transforms out to:

#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8


Here is one using GNU awk's asort:

$ awk 'BEGIN { FS="," }                     # define , as field separator{    p=( NR%2 ? $2 : p )              # every other record updates p    a[p]=a[p] (a[p]==""?"":ORS) $0   # second record in pair is appended to}                                    # first ORS separatedEND {    n=asort(a,b,"@ind_str_asc")      # sort on key    for(i=1;i<=n;i++)                # loop them        print b[i]                   # and output}' file#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8

It supports only unique keys in $2 Is groups records with equal $2 but does not order within that group, for example:

$ awk '{...}' file file#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8


Similar in structure to the answer from @Charles, but uses small awk scripts instead of the bash functions.

Save the following in its own file, named (for example) sortem.sh:

#!/usr/bin/env bashset -e[[ $# -ge 1 ]] && exec < "$1"awk -F , '/^#EXTINF/ {s=$0} /^http/ {print s FS $0}' | \  sort -t , -k 2,2 | \  awk -F , '{print $1 FS $2 "\n" $3}'

Make the file executable via:

$ chmod +x sortem.sh

Identify the file where the input to be processed is saved. For example, you might save it in a file named sortem_input.txt. Using cat to display this file's contents shows:

$ cat sortem_input.txt#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8

Process this input using an invocation like:

$ ./sortem.sh sortem_input.txt

...or:

$ ./sortem.sh < sortem_input.txt 

...or more generally:

$ <commands that generate input> | ./sortem.sh

The output looks like:

#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HDhttp://StreamUrl.m3u8#EXTINF:-1 tvg-logo="http://YetAnotherRandomUrl.com/icon.png",Discoveryhttp://DisStreamUrl.m3u8#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBChttp://AnotherStreamUrl.m3u8