Awk: создание файла icalendar.Как напечатать несколько последовательных строк? - PullRequest
0 голосов
/ 31 мая 2019

Благодаря ответу Эда Мортона я смог провести некоторое тестирование с помощью Thunderbird и валидатора icalendar. Я отредактировал свой вопрос, добавив записи без описания и ожидаемый результат с точными требованиями.

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

lun 06 05 2019 08 15 09 00 F206
    A descritpion text.
ven 10 05 2019 11 00 11 45 G202
    Another description text
    - on multiple; 
    - lines.
lun 13 05 2019 08 15 09 00 F206
ven 17 05 2019 11 00 11 45 G202
    A long description with more than 75 characters.
    This happen often when multiple lines are
    joined in one. So the program shoud split every lines
    To 75 characters including the word description.
lun 20 05 2019 08 15 09 00 F206
    A description text.

Мой скрипт выглядит так, я новичок в awk:

#!/bin/bash
awk ' BEGIN { print "BEGIN:VCALENDAR\r\n\
... some entries here ...\r\n\
END:VTIMEZONE\r" ;}
$1~/^(lun|mar|mer|jeu|ven)$/ { print "BEGIN:VEVENT\r\n\
... some entries here ...\r\n\
DTSTART;TZID=Europe/Zurich:"$4""$3""$2"T"$5""$6"00\r\n\
DTEND;TZID=Europe/Zurich:"$4""$3""$2"T"$7""$8"00\r\n\
TRANSP:OPAQUE\r\n\
DESCRIPTION: >>>HERE I NEED THE DESCRIPTIVE LINES<<<< \r\n\
END:VEVENT\r"}
END { print "END:VCALENDAR" } ' < $1 > $1.ics

ожидаемый результат:

BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20190506T081500
DTEND;TZID=Europe/Zurich:20190506T090000
DESCRIPTION:A descritpion text.
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20190510T110000
DTEND;TZID=Europe/Zurich:20190510T114500
DESCRIPTION:Another description text\n- on multiple;\n- lines.
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20190513T081500
DTEND;TZID=Europe/Zurich:20190513T090000
END:VEVENT                  
BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20190517T110000
DTEND;TZID=Europe/Zurich:20190517T114500
DESCRIPTION:A long description with more than 75 characters.\nThis happen
 often when multiple lines are\njoined in one. So the program shoud split 
 every lines\nTo 75 characters including the word description.
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20190520T081500
DTEND;TZID=Europe/Zurich:20190520T090000
DESCRIPTION: A description text.
END:VEVENT
END:VCALENDAR

Итак, точные требования:

  1. Строки без описания не должны печатать. ОПИСАНИЕ:.
  2. Многострочное описание должно быть разделено литералом \ n. Это работает с printf "%s%s", $0, "\\n"
  3. Строки должны быть разделены до менее чем 75 символов, заканчивающихся символом \ r \ n
  4. Строки дополнительного описания должны начинаться с пробела.

Ответы [ 2 ]

1 голос
/ 31 мая 2019
$ cat tst.awk
BEGIN {
    ORS="\r\n"

    print "BEGIN:VCALENDAR"
    print "... some entries here ..."
    print "END:VTIMEZONE"
}
/^[^[:space:]]/ {
    prtEndVevent()

    print "BEGIN:VEVENT"
    print "... some entries here ..."

    date = $4 $3 $2
    begt = $5 $6 "00"
    endt = $7 $8 "00"

    print "DTSTART;TZID=Europe/Zurich:" date "T" begt
    print "DTEND;TZID=Europe/Zurich:"   date "T" endt
    next
}
{
    gsub(/^[[:space:]]+|[[:space:]]+$/,"")
    desc = (desc == "" ? "DESCRIPTION:" : desc RS) $0
}
END {
    prtEndVevent()
    print "END:VCALENDAR"
}

function prtEndVevent(       wid) {
    if ( desc != "" ) {
        wid = 74
        gsub(RS,"\\n",desc)
        while ( desc !~ /^ ?$/ ) {
            print substr(desc,1,wid)
            desc = " " substr(desc,wid+1)
        }
        desc = ""
    }
    if ( endVevent != "" ) {
        print endVevent
    }
    endVevent = "END:VEVENT"
}

.

$ awk -f tst.awk file
BEGIN:VCALENDAR
... some entries here ...
END:VTIMEZONE
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190506T081500
DTEND;TZID=Europe/Zurich:20190506T090000
DESCRIPTION:A descritpion text.
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190510T110000
DTEND;TZID=Europe/Zurich:20190510T114500
DESCRIPTION:Another description text\n- on multiple;\n- lines.
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190513T081500
DTEND;TZID=Europe/Zurich:20190513T090000
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190517T110000
DTEND;TZID=Europe/Zurich:20190517T114500
DESCRIPTION:A long description with more than 75 characters.\nThis happen
 often when multiple lines are\njoined in one. So the program shoud split
 every lines\nTo 75 characters including the word description.
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190520T081500
DTEND;TZID=Europe/Zurich:20190520T090000
DESCRIPTION:A description text.
END:VEVENT
END:VCALENDAR

Обратите внимание, что это перенос по позициям символов, а не по границам слов, поэтому, если слово пересекает 75-ю позицию символа, оно будет разделено. Если это нежелательно, вы можете обновить prtDesc() для печати по одному слову за раз, проверив, будет ли общая длина всех напечатанных слов + пробелов плюс следующее слово меньше 75 (и решить, как обрабатывать строку описания, которая равна 75 + chars long без пробелов!) или вызовите команду UNIX fold, чтобы сделать перенос для вас.

Если вы когда-нибудь задумывались об использовании getline, обязательно сначала прочитайте и полностью поймите http://awk.freeshell.org/AllAboutGetline.

1 голос
/ 31 мая 2019

Вы действительно на правильном пути. Вот ваш скрипт, интегрированный с логикой flag:

#!/bin/bash
awk 'BEGIN {print "BEGIN:VCALENDAR\r\n\
... some entries here ...\r\n\
END:VTIMEZONE\r" ;}
$1~/^(lun|mar|mer|jeu|ven)$/ && flag {flag = !flag; print "END:VEVENT\r"}
$1~/^(lun|mar|mer|jeu|ven)$/ && !flag {flag = !flag; print "BEGIN:VEVENT\r\n\
... some entries here ...\r\n\
DTSTART;TZID=Europe/Zurich:"$4""$3""$2"T"$5""$6"00\r\n\
DTEND;TZID=Europe/Zurich:"$4""$3""$2"T"$7""$8"00\r\n\
TRANSP:OPAQUE\r\n\
DESCRIPTION: "; next}
flag {print $0}
END { print "END:VCALENDAR" } ' < $1

Выход:

BEGIN:VCALENDAR
... some entries here ...
END:VTIMEZONE
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190506T081500
DTEND;TZID=Europe/Zurich:20190506T090000
TRANSP:OPAQUE
DESCRIPTION:
    Some descriptive lines here.
    Lorem ipsumi dolor sit amet, consectetur adipiscing elitr.
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190510T110000
DTEND;TZID=Europe/Zurich:20190510T114500
TRANSP:OPAQUE
DESCRIPTION:
    sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
    - enim
    - ad minim veniam.
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190513T081500
DTEND;TZID=Europe/Zurich:20190513T090000
TRANSP:OPAQUE
DESCRIPTION:
    exercitation ullamco
END:VEVENT
BEGIN:VEVENT
... some entries here ...
DTSTART;TZID=Europe/Zurich:20190517T110000
DTEND;TZID=Europe/Zurich:20190517T114500
TRANSP:OPAQUE
DESCRIPTION:
    quis nostrud
END:VCALENDAR
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...