ubuntuusers.de

Suchen und ersetzen mit der Shell / ICS Kalender

Status: Gelöst | Ubuntu-Version: Ubuntu
Antworten |

Kasty

Anmeldungsdatum:
14. Januar 2010

Beiträge: Zähle...

Hallo und schon mal vielen Dank für die Hilfe.

Ich versuche eine Art öffentliche Kalender zu erzeugen indem aus den .ics Dateinen die privaten Daten durch "Privat" oder "" ersetze.

Grundsätzlichen sieht ein privater Termin so aus:

SUMMARY:Privatertesttermintitel
DTSTART;TZID=Europe/Berlin:20110904T130000
DTEND;TZID=Europe/Berlin:20110904T140000
CLASS:PRIVATE
LOCATION:PrivatertestterminOrt
DESCRIPTION:PrivatertestterminBeschr

Also würde ich gerne die Daten von SUMMARY, LOCATION und DESCRIPTION ersetzen. Natürlich gibt es noch jede Menge anderer Termine die ebenso SUMMARY, LOCATION und DESCRIPTION enhalten. Daher mussen SUMMARY vor CLASS:PRIVATE und LOCATION ,DESCRIPTION danach ersetzt werden. Ich glaube die Anzahl oder Position der Zeilen ändert sich nicht man könnte also einfach die 3. Zeile vor CLASS:PRIVATE durch SUMMARY: ersetzen und die 2 Zeilen danach durch LOCATION: und DESCRIPTION:.

Ich hab da schon einiges mit "sed", "vi(m)" und "grep" versucht bin aber leider nicht weiter gekommen.

Gruß Kasty

Vain

Avatar von Vain

Anmeldungsdatum:
12. April 2008

Beiträge: 2510

Servus,

versteh’ ich das jetzt richtig, dass es sich da um einzelne Dateien handelt? Nicht, dass es pro Datei mehrere Termine gibt. Dann könnte das so ähnlich aussehen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/bin/bash

# Iteriere über alle Dateien im aktuellen Verzeichnis, die auf ".ics"
# enden.
for i in *.ics
do
	# Wenn es eine "privat"-Zeile in der Datei gibt, dann ...
	if grep -q '^CLASS:PRIVATE$' "$i"
	then
		# ... ersetze die Felder.
		sed -i -r \
			-e 's/(SUMMARY:).*/\1Wir sind nicht öffentlich/' \
			-e 's/(LOCATION:).*/\1Ort nicht öffentlich/' \
			-e 's/(DESCRIPTION:).*/\1Beschreib dich doch selber!/' \
			"$i"
	fi
done

Sollte es komplizierter werden, dann gibt es bestimmt für Python ein bisschen passende Magie.

Kasty

(Themenstarter)

Anmeldungsdatum:
14. Januar 2010

Beiträge: 32

Danke für die schnelle Antwort. Zum Thema nunja die Anzahl der .ics-Dateien ist überschaubar. Die Anzahl der Termine nicht. Es kann also etliche Private und nicht private Termine geben.

Eine .ics-Datei enthält immer einen ganzen Kalender. Und ich möchte alle privaten Termine aus allen Kalendern annonmysieren. Es für eine Datei hin zu kriegen würde mir schon reichen den Rest schaff ich schon.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Liege ich richtig mit der Annahme, dass der Aufbau der einzelnen Termin-Eintragungen in der ICS-Datei immer ± so aussieht wie in Deinem Beispiel, und dass die einzelnen Datensätze einfach hintereinander gereiht sind ?
Und, dass vor allem die Reihenfolge der Datensätze innerhalb eines Termins immer gleich ist ?

Dann hieße die Aufgabe:

  1. Merke Dir die SUMMARY und sammle den Rest bis zur "CLASS"

  2. frage CLASS ab: "CLASS:PRIVATE" oder "CLASS:[andere]", merke Dir den Status und gib den gesammelten Text aus

  3. falls Status "PRIVATE": anonymisiere die betreffenden Zeilen.

Das ließe sich einigermaßen übersichtlich mit awk bewerkstelligen:

#! /usr/bin/awk -f

/^SUMMARY:/  {	summary=$0;
		class= ""							# Merker class löschen
		next  }								# und weiter


/^CLASS:/    {	class=substr($0,7);						# Merker class setzen
		if(class == "PRIVATE")  {					# privat:
			print "SUMMARY:privat"	}				# drucke "Ersatztext"
		else print summary						# sonst: Original-Summary

		printf text1;							# drucke 1.Textteil
		text1= "";  }							# und lösche ihn



     {	if(class == "") text1= text1 $0 "\n";					# 1.Textteil: sammeln

	else if(class == "PRIVATE")  {						# 2.Textteil privat:
		if($0 ~ "^LOCATION:") print "LOCATION:privat";			# drucke "Ersatztext"
		else if($0 ~ "^DESCRIPTION:") print "DESCRIPTION:privat";	# drucke "Ersatztext"
		else print $0;							# sonst: Originalzeile
		}
	else print $0;								# andere CLASS: Originalzeile
	}

Wie gewohnt das Skript "ausführbar" machen und mit ./script quelldatei.ics > zieldatei.ics aufrufen.
Um das Skript zu verstehen, solltest Du Dich in der Einfuhrung awk einlesen.

LG,

track

Kasty

(Themenstarter)

Anmeldungsdatum:
14. Januar 2010

Beiträge: 32

Das is die Fehlermeldeung die die Konsole zuück gibt.

./privat.sh: line 6: vergrößern: command not found
./privat.sh: line 10: /^SUMMARY:/: No such file or directory
./privat.sh: line 11: : command not found
./privat.sh: line 12: next: command not found
./privat.sh: line 15: syntax error near unexpected token `('
./privat.sh: line 15: `/^CLASS:/    {   class=substr($0,7);                                             # Merker class setzen'

Vielen dank überigens für den Tip mit awk.

Gruß Kasty

Vain

Avatar von Vain

Anmeldungsdatum:
12. April 2008

Beiträge: 2510

Kasty schrieb:

Das is die Fehlermeldeung die die Konsole zuück gibt.

Da ging aber irgendwas deftig in die Hose. ☺ Ich frage mich, was. Schon das Wort „vergrößern“ taucht weder bei track noch bei mir auf. Du wirst wohl mal haarklein aufschreiben müssen, was du wie getan hast, um diesen Fehler zu erhalten, damit man dir helfen kann.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11269

Wohnort: München

@Kasty: du gibst die Struktur einer iCalendar-Datei etwas verkürzt wieder... Hier mal ein Beispiel mit zwei Einträgen aus einem Kalender von 2009, damit die anderen Wissen, was da an Konstrukt um die Termine herum ist:

BEGIN:VCALENDAR
CALSCALE:GREGORIAN
METHOD:PUBLISH
PRODID:-//From my Skript//carpe diem//
VERSION:2.0
X-WR-CALNAME:MeCuM
X-WR-TIMEZONE:Europe/Belgrade
BEGIN:VEVENT
DESCRIPTION:Gruppe: B
DTEND:20090602T134500
DTSTAMP:20090623T121020Z
DTSTART:20090602T121500
CLASS:PRIVATE
LOCATION:XXXXX
UID:100020090602T121500
END:VEVENT
BEGIN:VEVENT
DESCRIPTION:Gruppe: C Untergruppe: 4
DTEND:20090603T130000
DTSTAMP:20090623T121020Z
DTSTART:20090603T090000
CLASS:PUBLIC
LOCATION:Treffpunkt: XXXXX
UID:300120090603T090000
END:VEVENT
END:VCALENDAR

Im Prinzip geht ein Event vom BEGIN:VEVENT bis zum END:VEVENT - es gibt für Python auch ein nettes Modul (icalendar, auch in den Paketquellen von Ubuntu verfügbar) Mit dem man Events auch relativ leicht anhand von Kriterien filtern und manipulieren kann.

Edit Skriptbeispiel entfernt, da nicht funktional...

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Kasty schrieb:

Das is die Fehlermeldeung die die Konsole zuück gibt. ...

Das sieht doch so aus, als wenn Du das awk- Skript an die Shell verfüttert hast ...!?

Das ist ein awk- Skript.
Wenn Du es brav genau so aufrufst wie beschrieben, dann wird es dank des She-bang auch automatisch von awk ausgeführt. 😉

Hat bei Dir die komplette Kalenderdatei auch das Drumherum das seahawk1986 beschreibt ? -dann muss mein Skript nämlich noch angepasst werden.

track

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11269

Wohnort: München

Laut der RFC sollte die grobe Struktur schon vorhanden sein, wenn das eine echte iCalendar-Datei ist: http://www.ietf.org/rfc/rfc2445.txt

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Ja, die Spec hatte ich mir heute Mittag schon mal angeguckt, aber sie war mir erstmal zu umfangreich und unübersichlich ... 😉

Aber wenn man dort mal das Beispiel auf S.136 nimmt, dann heißt das, dass die beiden Trigger BEGIN:VEVENT und END:VEVENT immer vorhanden sind, der Rest kann aber durchaus auch eine andere Reihenfolge haben. ... also doch ganz andere Vorgaben.

Die lassen sich natürlich auch umsetzen:

  1. reich erstmal alles durch ...

  2. ab BEGIN:VEVENT lies alles in ein Array ein und frage ab, ob CLASS:PRIVATE ist.

  3. bei END:VEVENT gib das Array entweder direkt oder gefiltert aus, je nachdem

  4. weiter mit Punkt 1.

Konkret könnte das mit awk z.B. so aussehen:

#! /usr/bin/awk -f

     {	if($0 == "BEGIN:VEVENT")  {
		i= 1;
		while($0 != "END:VEVENT")  {						# für ganzen "VEVENT"-Block 
			if($0 ~ "^CLASS:") class= substr($0,7);				# Marker "class" abnehmen
			text[i++]= $0;							# in Array
			getline								# einlesen ..
			}
		if(class == "PRIVATE") for(j=1; j<i; j++)  {				# privat:
			if(text[j] ~ "^SUMMARY:") print "SUMMARY:privat";		# drucke "Ersatztexte"
			else if(text[j] ~ "^LOCATION:") print "LOCATION:privat";	#
			else if(text[j] ~ "^DESCRIPTION:") print "DESCRIPTION:privat";	#
			else print text[j];						# sonst: ungefiltert
			}
		else  for(j=1; j<i; j++) print text[j];					# andere CLASS: ungefiltert
		}
	print $0									# Rest durchreichen
	}

LG,

track

Kasty

(Themenstarter)

Anmeldungsdatum:
14. Januar 2010

Beiträge: 32

Das ist der Kalender vor ausführung des Skripts von track

BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
METHOD:PUBLISH
X-WR-CALNAME:fsc
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20110928T095307Z
LAST-MODIFIED:20110928T100733Z
DTSTAMP:20110928T100733Z
UID:dd6d6fe4-bdce-4c47-9ec6-67a2adf63b8b
SUMMARY:pr!vat
DTSTART;TZID=Europe/Berlin:20110828T120000
DTEND;TZID=Europe/Berlin:20110828T130000
LOCATION:pr!vat
DESCRIPTION:pr!vat
CLASS:PRIVATE
SEQUENCE:1
X-MOZ-GENERATION:1
END:VEVENT
END:VCALENDAR

Und das ist die Rückgabe des Skripts

BEGIN:VCALENDAR
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
VERSION:2.0
METHOD:PUBLISH
X-WR-CALNAME:fsc
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20110928T095307Z
LAST-MODIFIED:20110928T100733Z
DTSTAMP:20110928T100733Z
UID:dd6d6fe4-bdce-4c47-9ec6-67a2adf63b8b
SUMMARY:pr!vat
DTSTART;TZID=Europe/Berlin:20110828T120000
DTEND;TZID=Europe/Berlin:20110828T130000
LOCATION:pr!vat
DESCRIPTION:pr!vat
CLASS:PRIVATE
SEQUENCE:1
X-MOZ-GENERATION:1
END:VEVENT
END:VCALENDAR

Scheinbar hat sich nichts verändert

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Komisch, bei mir wird 3x brav das "pr!vat" durch "privat" ersetzt.

Welche Version awk hast Du denn ? (was gibt awk --version aus ?)
Und, hast Du die Datei womöglich unter Win.. erstellt, dass sie falsche Zeilenenden hat ? (was zeigt grep CLASS [deinequelldatei] | hd ?)

track

Kasty

(Themenstarter)

Anmeldungsdatum:
14. Januar 2010

Beiträge: 32

Meine Version ist AWK 3.1.7

GNU Awk 3.1.7
Copyright (C) 1989, 1991-2009 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.

Ich habe das Skript direkt über die SSH-Shell in die Datei kopiert.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Kurze Nachfrage: Wäre es nicht sinnvoller, diese Termine einfach aus dem Kalender zu löschen?

Kasty

(Themenstarter)

Anmeldungsdatum:
14. Januar 2010

Beiträge: 32

Ich hab grad festgestellt wenn das Skript nur aus einem Eintrag besteht funktioniert das Skript. Wenn es ein ganzern Kalender ist funktioniert es nicht.

Ich werd einfach mal mit grep den Anfang und das Ende eines Termins nehmen und das nacher wieder zusammenfügen.

Antworten |