.ics 파일의 항목이 다른 행의 현재 항목과 일치하는 경우 해당 항목을 바꾸려고 합니다 VEVENT
(내보내기가 올바르지 않음).VTODO
date
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART:20220340T140000
END:VEVENT
BEGIN:VEVENT
DTSTART:20230620T193700
END:VEVENT
BEGIN:VEVENT
DTSTART:20210210T193800
END:VEVENT
END:VCALENDAR
두 번째 VEVENT 항목에는 현재 시간이 있으므로 다음과 같아야 합니다.
BEGIN:VTODO
DTSTART:20230620T193700
END:VTODO
BEGIN:VEVENT
와 행 사이에 더 많은 항목이 있으므로 END:VEVENT
명확성을 위해 편집했습니다.
sed로 이것을 시도했지만 범위는 첫 번째 발생이 아닌 전체 파일에서 VEVENT의 첫 번째 발생을 선택합니다.뒤쪽에(또는 이전) 일치하는 패턴이므로 모든 패턴을 대체합니다.
sed -i "/BEGIN:VEVENT/,/DTSTART:$(date +%Y%m%dT%H%M)/{s/VEVENT/VTODO/}" org.ics
나는 이것을 관련이 있다고 생각하는 또 다른 질문에 적용하려고 노력하고 있습니다.문자열을 찾고 첫 번째 문자열을 찾은 후 다른 문자열을 바꿉니다.
sed -n "/DTSTART:$(date +%Y%m%dT%H%M)/,${/END:VEVENT/{x//{x b}g s/VEVENT/VTODO/}}" org.ics
하지만 전혀 작동하지 않습니다:
sed: -e expression #1, char 25: unexpected
,''
답변1
따라서 다음이 작동합니다.
sed 'H;/BEGIN:VEVENT/h;/END:VEVENT/!d;x;/DTSTART:'"$(date +%Y%m%dT%H%M)"'/s/VEVENT/VTODO/g' org.ics
설명하다:
H
: 버퍼(공간)를 생성하기 위해 예약된 공간을 추가한 다음 패턴 매칭을 수행합니다.
/BEGIN:VEVENT/h
예약된 공간에 저장하므로 이제 또 다른 패턴 일치를 실행합니다.
/END:VEVENT/!d
패턴이 일치하지 않으면 제거됩니다.
x;
공간을 유지하기 위해 패턴 공간과 교체하므로 이제 패턴 공간에 필요한 행이 있습니다.
DTSTART...
마지막으로 행이 날짜와 일치하면 행을 바꿉니다. so는 s/.../.../g
일치하는 경우에만 실행됩니다.
/DTSTART:'"$(date +%Y%m%dT%H%M)"/s/VEVENT/VTODO/g
고쳐 쓰다
sed '1n;H;/BEGIN:VEVENT/h;/END:VEVENT/!d;x;/DTSTART:'"$(date +%Y%m%dT193700)"'/s/VEVENT/VTODO/g' org.ics | sed '$aEND:CALENDAR
답변2
모든 Unix 시스템의 모든 쉘에서 awk를 강력하게 사용하십시오.
$ cat tst.sh
#!/usr/bin/env bash
awk -v now="$(date +'%Y%m%dT%H%M')" '
$0 == "BEGIN:VEVENT" {
eventType = 1
event = $0
next
}
eventType {
event = event ORS $0
if ( $0 == ("DTSTART:" now) ) {
eventType = 2
}
if ( $0 == "END:VEVENT" ) {
if ( eventType == 2 ) {
sub(/^BEGIN:VEVENT/,"BEGIN:VTODO",event)
sub(/END:VEVENT$/,"END:VTODO",event)
}
print event
}
next
}
{ print }
' "${@:--}"
$ ./tst.sh file
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART:20220340T140000
END:VEVENT
BEGIN:VTODO
DTSTART:20230620T193700
END:VTODO
BEGIN:VEVENT
DTSTART:20210210T193800
END:VEVENT
이것이 실패하는 유일한 방법은 입력에 BEGIN:, END: 또는 DSTART: 줄과 일치하는 줄을 포함할 수 있는 다른 섹션이 있을 수 있지만 이것이 입력에서 작동할지는 의문입니다. 그렇다면, 우리는 그것이 어떻게 지정되는지 보여주어야 합니다.
위 솔루션에서 중요한 점은 입력에 나타날 수 있는 부분 일치뿐만 아니라 전체 텍스트 줄을 대상 문자열과 비교한다는 것입니다.
답변3
해결책은 아니며 힌트만 제공합니다.
sed s/'$'/':'/ org.ics |awk 'BEGIN{RS="BEGIN";FS=":";CD="20220340"} NR>1 {AA[1]="BEGIN";for(i=2;i<=NF;i++){AA[i]=$i;if($i =="DTSTART" && $(i+1) ~ CD ){AA[2]="VTODO"}};for(i in AA){printf AA[i]":"};print ""}'
여기서 sed
명령은 각 줄 끝에 :(콜론)을 추가하고 RS="BEGIN"
RowSeparator를 BEGIN 키워드로 설정하고(그래서 무시합니다!) FS=":"
FieldSeparator를 ":"으로 설정합니다. 각 "행"(키워드 BEGIN에서 다음 BEGIN까지, "레코드"라고 말하는 것이 더 좋음)에서 AA[i]
AA[1]은 BEGIN을 무시해야 하므로 필드는 i=2로 시작하는 배열 멤버에 복사됩니다. DTSTART 키워드와 현재 날짜를 모두 확인하고 필요한 경우 VEVENT를 VTODO로 변경합니다. 행을 확인한 후 배열 AA[]가 :를 구분 기호로 사용하여 인쇄됩니다.
이것은 단지 힌트일 뿐이며 테스트해 보지 않았습니다. 직접 디버깅하고 조정해야 합니다. 즉, 필요하지 않은 경우 후행을 지울 수 있습니다.
답변4
우리는 이런 해결책을 가질 수 있습니다TxR:
@(repeat)
@ (cases)
BEGIN:VEVENT
DTSTART:@{date}T@{time}
END:VEVENT
@ (output)
BEGIN:VTODO
DTSTART:@{date}T@{time}
END:VTODO
@ (end)
@ (or)
@line
@ (do (put-line line))
@ (end)
@(end)
이는 그 자체로 모든 항목을 다음에 다시 작성합니다 VTODO
.
$ txr cal.txr cal.ics
BEGIN:VCALENDAR
BEGIN:VTODO
DTSTART:20220340T140000
END:VTODO
BEGIN:VTODO
DTSTART:20230620T193700
END:VTODO
BEGIN:VTODO
DTSTART:20210210T193800
END:VTODO
END:VCALENDAR
date
명령줄에서 바인딩 및 변수를 사용할 수 있습니다 .time
$ txr -Ddate=20230620 cal.txr cal.ics
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART:20220340T140000
END:VEVENT
BEGIN:VTODO
DTSTART:20230620T193700
END:VTODO
BEGIN:VEVENT
DTSTART:20210210T193800
END:VEVENT
END:VCALENDAR
이제 두 번째 항목만 일치하고 다시 작성됩니다.
예쁜 버전: