Сортировка пар строк по одному полю в одной из этих строк

Я пытаюсь преобразовать поток как:

#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

В:

#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

... сортируя по второму разделенному запятыми полю строк, начинающихся с #, переупорядочивая другие строки рядом с теми, что с ключами сортировки.

Поэтому я выполняю сортировку только по строкам, содержащим "#EXTINF", и сортирую после ",". Следует также сохранить строку ниже (строка URL) отсортированной строки с ним.

3 ответа

Вот один, использующий 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 separated
END {
    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 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

Он поддерживает только уникальные ключи в$2 Является ли группа записей с равными $2 но не заказывает в этой группе, например:

$ awk '{...}' file file
#EXTINF:-1 tvg-logo="http://randomUrl.com/icon.png",ABC HD
http://StreamUrl.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
#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
#EXTINF:-1 group-title="SERVER 1-Tv" tvg-logo="http://anotherRandomUrl.com/icon.png",NBC
http://AnotherStreamUrl.m3u8

Преобразуйте ваши данные в легко сортируемый формат, а затем сортируйте их обратно. Так:

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

С вашим данным входом, выход to_one_line_per_record является:

#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

Проходя через это sort -t, -k2,2, вывод становится:

#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

И передавая это через from_one_line_per_record, это превращается в:

#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

По структуре похож на ответ от @Charles, но использует маленький awk скрипты вместо функций bash.

Сохраните следующее в своем собственном файле с именем (например) sortem.sh:

#!/usr/bin/env bash

set -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}'

Сделайте файл исполняемым через:

$ chmod +x sortem.sh

Определите файл, в котором сохраняются входные данные для обработки. Например, вы можете сохранить его в файле с именем sortem_input.txt, С помощью cat для отображения содержимого этого файла показывает:

$ cat sortem_input.txt
#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

Обработайте этот ввод, используя такой вызов:

$ ./sortem.sh sortem_input.txt

...или же:

$ ./sortem.sh < sortem_input.txt 

... или вообще:

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

Вывод выглядит так:

#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
Другие вопросы по тегам