二重一致 - 前の行が他のパターンと一致する場合は、後続の行のパターンを変更しますか?

二重一致 - 前の行が他のパターンと一致する場合は、後続の行のパターンを変更しますか?

.icsファイルのエントリが他の行の現在のエントリと一致する場合は、そのエントリを置き換えようとしますVEVENT(エクスポートが正しくありません)。VTODOdate

BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART:20220340T140000
END:VEVENT
BEGIN:VEVENT
DTSTART:20230620T193700
END:VEVENT
BEGIN:VEVENT
DTSTART:20210210T193800
END:VEVENT
END:VCALENDAR

2番目の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

これで、2番目の項目だけが一致して再作成されます。

かなりバージョン:

Vimの構文を強調

関連情報