LINUX.ORG.RU

Sed нет больше моих сил

 , ,


0

1

Выручайте, заманался я с сабжем Есть кривой IPTV плейлист. Мне в нем нужно заменить кривые названия групп на правильные, с этим проблем не возникло. В плейлисте есть мертвые ссылки, хочу удалить такую ссылку и строку над ней. Пример

#EXTINF:-1 group-title="Фильмы",A1
http://iptv.tv/amedia/playlist.m3u8
#EXTINF:-1 group-title="Фильмы HD",A1 HD
http://iptv.tv/amediahd/playlist.m3u8
Нужно вместо Фильмы HD сделать Фильмы и удалить строку по маске amediahd + предыдущую. Скрипт
#!/bin/bash
sed 's/Фильмы|HD/Фильмы/' original.m3u8 >> new.m3u8
Такая конструкция меняет название и пишет все в новый плейлист. Могу в консоли выполнить вторую часть задачи вот так
sed -n '/amediahd/{s/.*//;x;d;};x;p;${x;p;}' original.m3u8 | sed '/^$/d' > new.m3u8
Не могу все это запихнуть в скрипт. Можно создавая промежуточные плейлисты добиться результата, но не хочу. Подскажите кто знает толк в sed или awk

Из твоего описания следует, что ты сначала зачем то меняешь подстроку Фильм ХД на Фильм, а потом строку с этой подстрокой удаляешь. Зачем? Удаляй сразу без замены по двум маскам - Фильм ХД и amediahd.

anonymous
()

окей, гугл, «sed remove previous line»

You can revert the file and then delete the line after the matche pattern(which is simple), and then revert the result, here is the code:

tail -r|sed '/pattern/{n;d;}'|tail -r
aol ★★★★★
()
Ответ на: комментарий от aol

А как это в скрипт запихнуть

#!/bin/bash
sed 's/Фильмы|HD/Фильмы/' original.m3u8 >> new.m3u8
? В консоли я в посте написал как решается задача, эту команду не могу в скрипт добавить без колхоза

achilles_85
() автор топика
Ответ на: комментарий от achilles_85

В описании лишь пример, в плейлисте под 500 ссылок

Всего то?! Я то думал. Ну в принципе можно и напрограммить, но такое проще редактором с макросами обработать: найти->подняться на строку->удалить строку,удалить строку->повторить.

vodz ★★★★★
()

Ты рассуждаешь в терминах строк, а нужно думать о записях. Считываешь запись целиком, затем принимаешь решение удалить её или оставить. Это легко делается на sh и на awk (и на других яп), а grep и sed работают со строками, а не с записями и не подходят, поэтому ты испытываешь дискомфорт.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs
exec < original.m3u8 > new.n3u8
while IFS= read -r extinf && IFS= read -r url; do
  if isurlok "$url"; then
    printf '%s\n%s\n' "$extinf" "$url"
  fi
done

(пишу с мобилы, не проверял)

legolegs ★★★★★
()
Последнее исправление: legolegs (всего исправлений: 1)

Если строки строго идут парами (нечётные - с «#», чётные - с url) и amediahd может быть только в url (т.е. в чётной), то просто:

sed -r 'N; /amediahd/ d' < original.m3u8 > new.m3u8

Если нет, тогда сложнее:

sed -r '1 { /amediahd/ d; };   $ ! { /\n/ ! N;  /amediahd/ d;  P; D; }' < original.m3u8 > new.m3u8
spirit ★★★★★
()
Ответ на: комментарий от spirit

sed -r '1 { /amediahd/ d; }; $ ! { /\n/ ! N; /amediahd/ d; P; >D; }' < original.m3u8 > new.m3u8

Такая конструкция работает, чётные - с «#», нечётные - с url. Но Вот так не работает

sed -r '1 { /amediahd/ d; };   $ ! { /\n/ ! N;  /amediahd/ d;  P; D; }; 1 { /amediahd2/ d; };   $ ! { /\n/ ! N;  /amediahd2/ d;  P; D; }' < original.m3u8 > new.m3u8
Удаляются только строки с
amediahd
. Где ошибка?

achilles_85
() автор топика
Последнее исправление: achilles_85 (всего исправлений: 1)
Ответ на: комментарий от anonymous

Напиши программу на нормальном языке (скажем, Go), да и всё.

+1. Нафига пытаться решить задачу на инструменте, который для этого не предназначается? Регеспы созданы для того, чтобы находить какие-либо подпоследовательности в строках. Все. Если что-то не укладывается в эту задачу, значит инструмент не верный.

Всевозможные расширения регекспов, позволяющие возвращаться назад или заглядывать вперед, скорее всего, были разработаны не от хорошей жизни, а когда у тебя есть уже сложная работающая программа на регекспах и вдруг появляется ситуация, когда появляются случаи, которые невозможно решить при помощи простых регекспов.

Если же начинать писать новую программу, то нет смысла сразу влазить в это говно. Возьми любой другой нормальный императивный язык, который хоть как-то знаешь. Там работы на пол часа, если часто использыешь язык или на час, если с гуглением и копипастом из стаковерфлоу.

anonymous
()
Ответ на: комментарий от anonymous

Регеспы созданы для того, чтобы находить какие-либо подпоследовательности в строках.

Да не, сами регекспы по умолчанию как раз на \n не реагируют и надо дополнительно флаги ставить REG_NEWLINE, REG_NOTBOL, REG_NOTEOL (man regex). Вот утилиты, те да... Обычно строчные. Кстати, grep вот умеет показывать до и после строки, впрочем оно только для человека в этом режиме удобно, для скриптов оно неоднозначно получается.

vodz ★★★★★
()
#!/bin/bash

while true
do
	read -r line || break
	if [[ $line =~ ^#EXTINF ]]
	then
		# прочитали extinf
		extinf=$line
		# следующая строка - url
		read -r url || break
	else
		# не extinf - значит это url
		extinf=
		url=$line
	fi

	# тут заменяем инфу в extinf
	extinf="${extinf/Фильмы HD/Фильмы}"

	# тут пропускаем ненужные url
	[[ $url =~ amediahd ]] && continue

	# если url с extinf - выводим extinf
	[[ "$extinf" ]] && echo "$extinf"

	# сам догадайся что здесь
	echo "$url"
done
anonymous
()

Можно создавая промежуточные плейлисты добиться результата, но не хочу.

Ерундой вы страдаете. Создавать промежуточные файлы для решения задачи sh-скриптами это нормально. А сочинив многоэтажное sed-выражение (или скопировав его с форума) усложните себе жизнь через год-другой, когда понадобиться что-то поправить, а вы нифига не вспомните, как эта конструкция работает.

mky ★★★★★
()
Ответ на: комментарий от vodz

Кстати, grep вот умеет показывать до и после строки, впрочем оно только для человека в этом режиме удобно, для скриптов оно неоднозначно получается.

Кстати, это хорошая идея для решения этой конкретной задачи с грепом с флагом -B 1, если удастся написать регесп на валидные урлы

cat inpfile.txt | grep -B 1 -P 'valid url regexp' > resultfile.txt
anonymous
()
Ответ на: комментарий от achilles_85

Но Вот так не работает

Странно, у меня работает:

$ printf '%s\n' 1amediahd 2 3 4amediahd 5 6 7
1amediahd
2
3
4amediahd
5
6
7
$ printf '%s\n' 1amediahd 2 3 4amediahd 5 6 7 | sed -r '/amediahd/ d;  /\n/ ! N;  /amediahd/ d;  P; D;'
2
5
6
7
$ printf '%s\n' 1 2 3amediahd 4amediahd 5 6 7 | sed -r '/amediahd/ d;  /\n/ ! N;  /amediahd/ d;  P; D;'
1
5
6
7
$ printf '%s\n' 1 2 3amediahd 4 5 6amediahd 7 | sed -r '/amediahd/ d;  /\n/ ! N;  /amediahd/ d;  P; D;'
1
4
7
spirit ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.