Moin,
habe erst vor kurzem angefangen mit python und habe jetzt ein Problem mit dem ich einfach nicht mehr weiterkomme.
Ich möchte in einer cfg datei nach einem Abschnitt suchen und diesen in eine weitere Datei schreiben.
Der Abschnitt geht über 3-15 Zeilen und ist von Datei zu Datei unterschiedlich.
Der Abschnitt fängt mit "{" an und hört mit "}" auf.
Vielen Dank schon mal im Vorraus
.cfg Daten auswerten
@kimaro: Was ist denn das konkrete Problem dabei? Nach der bisherigen Beschreibung musst Du doch nur die Datei in eine Zeichenkette einlesen, die Positionen beiden Klammern finden, den Teil ”ausschneiden”, und in eine neue Datei schreiben. Zum finden der Position haben Zeichenketten die `index()`-Methode. ”Ausschneiden” geht mit der „slice”-Syntax. Das sollte eigentlich alles in einem Grundlagentutorial dran kommen. Ausser `index()` vielleicht. Die Methoden auf Zeichenketten, sollte man sich alle mal anschauen. Wie eigentlich die Methoden auf allen Grunddatentypen.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Um mal alle Eventualitäten auszuschließen: Kannst Du uns mal eine Beispieldatei posten? Und: Weißt Du, ob es sich um ein bekanntes Format handelt? Und: Kannst Du ausschließen, dass es sich um JSON handelt?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Hi,
erstmal vielen Dank für die Antworten.
Habe jetzt schon mehrere Versuche unternommen diese Stelle zu suchen und überhaupt auszugeben.
Dieser gibt mir jedoch gar nichts aus.
Tut mir leid bin echt noch ein blutiger Anfänger
erstmal vielen Dank für die Antworten.
Habe jetzt schon mehrere Versuche unternommen diese Stelle zu suchen und überhaupt auszugeben.
Code: Alles auswählen
while a == 1:
c = c + 1
try:
o = pfad + cfg[c]
# print(o)
if 'define host{' in open(o).read():
for zeile in open(o).read():
m = re.match(r"define host (})", zeile)
if m != None:
print(m.group ())
print(zeile)
Tut mir leid bin echt noch ein blutiger Anfänger
@kimaro: Das sieht alles ein wenig unkoordiniert und geraten aus. Teil das Problem in kleinere Teile auf und versuche nicht alles in einem grossen Code-Klumpen zu lösen. Schreibe zum Beispiel eine Funktion die *eine* Datei verarbeitet. Erst wenn die funktioniert eine die mehrere Dateien verarbeitet in dem sie die funktion die eine Datei verarbeitet für jeden Dateinamen aufruft.
Gewöhn dir auch gleich diese einbuchstabigen Namen ab. Namen sollten dem Benutzer vermitteln was der Wert bedeutet. Kein Mensch rät auf anhieb das `o` ein Pfad zu einer Konfigurationsdatei ist. Einbuchstabige Namen sind okay für die üblichen Laufvariablen aus der Mathematik, also beispielsweise `i` und `j`, wenn man da nur ganze Zahlen dran bindet. Oder in sehr beschränkten Gültigkeitsbereichen wie „list comprehensions” (LCs), Generatorausdrücken, oder ``lambda``-Definitionen. Ansonsten sollte man in Worten ausschreiben was gemeint ist. Zum Beispiel `path` statt `o`.
Das ``while a == 1:`` würde ich zu einem ``while True:`` machen und die Schleife falls nötig mit einem ``break`` verlassen. Ich gehe jetzt dabei davon aus das `a` nur die Werte 0 und 1 annimmt. Für solche Flags sollte man auch besser `True` und `False` verwenden.
Da `c` hochgezählt wird, kann man auch gleich eine ``for``-Schleife verwenden mit `c` als Laufvariable. Und da `c` als Index in `cfg` verwendet wird, vermute ich mal ganz stark, dass es für `c` auch eine Obergrenze gibt. Und ich hoffe das ``try`` ist nicht dazu da um diesen Fall abzudecken. Denn dann bräuchte man `c` überhaupt gar nicht, denn man kann in Python direkt über die Elemente von Containerobjekten iterieren, ohne einen Umweg über einen Index.
Pfadteile setzt man mit `os.path.join()` zusammen.
Dateien die man öffnet sollte man auch wieder schliessen. Am besten verwendet man ein `open()` immer zusammen mit einer ``with``-Anweisung.
Du liest die Datei für das ``if`` komplett in den Speicher, suchst nach der Teilzeichenkette und verwirfst die eingelesenen Daten, nur um in der nächsten Zeile die selbe Datei wieder komplett in den Speicher zu lesen. Das ist nicht wirklich effizient.
`zeile` ist ein falscher Name für etwas was keine Zeile darstellt. Schau Dir mal die Werte an, die an diesen Namen gebunden werden.
Zumindest für den regulären Ausdruck den Du da verwendest braucht man keine regulären ausdrücke. *Das* hättest Du auch wieder mit dem ``in``-Operator prüfen können. Allerdings habe ich den verdacht, dass das nicht das ist was geprüft werden soll an der Stelle.
Aber bevor wir weiter raten wie die Dateien tatsächlich aussehen, geh doch mal bitte auf die Fragen von Hyperion ein.
Gewöhn dir auch gleich diese einbuchstabigen Namen ab. Namen sollten dem Benutzer vermitteln was der Wert bedeutet. Kein Mensch rät auf anhieb das `o` ein Pfad zu einer Konfigurationsdatei ist. Einbuchstabige Namen sind okay für die üblichen Laufvariablen aus der Mathematik, also beispielsweise `i` und `j`, wenn man da nur ganze Zahlen dran bindet. Oder in sehr beschränkten Gültigkeitsbereichen wie „list comprehensions” (LCs), Generatorausdrücken, oder ``lambda``-Definitionen. Ansonsten sollte man in Worten ausschreiben was gemeint ist. Zum Beispiel `path` statt `o`.
Das ``while a == 1:`` würde ich zu einem ``while True:`` machen und die Schleife falls nötig mit einem ``break`` verlassen. Ich gehe jetzt dabei davon aus das `a` nur die Werte 0 und 1 annimmt. Für solche Flags sollte man auch besser `True` und `False` verwenden.
Da `c` hochgezählt wird, kann man auch gleich eine ``for``-Schleife verwenden mit `c` als Laufvariable. Und da `c` als Index in `cfg` verwendet wird, vermute ich mal ganz stark, dass es für `c` auch eine Obergrenze gibt. Und ich hoffe das ``try`` ist nicht dazu da um diesen Fall abzudecken. Denn dann bräuchte man `c` überhaupt gar nicht, denn man kann in Python direkt über die Elemente von Containerobjekten iterieren, ohne einen Umweg über einen Index.
Pfadteile setzt man mit `os.path.join()` zusammen.
Dateien die man öffnet sollte man auch wieder schliessen. Am besten verwendet man ein `open()` immer zusammen mit einer ``with``-Anweisung.
Du liest die Datei für das ``if`` komplett in den Speicher, suchst nach der Teilzeichenkette und verwirfst die eingelesenen Daten, nur um in der nächsten Zeile die selbe Datei wieder komplett in den Speicher zu lesen. Das ist nicht wirklich effizient.
`zeile` ist ein falscher Name für etwas was keine Zeile darstellt. Schau Dir mal die Werte an, die an diesen Namen gebunden werden.
Zumindest für den regulären Ausdruck den Du da verwendest braucht man keine regulären ausdrücke. *Das* hättest Du auch wieder mit dem ``in``-Operator prüfen können. Allerdings habe ich den verdacht, dass das nicht das ist was geprüft werden soll an der Stelle.
Aber bevor wir weiter raten wie die Dateien tatsächlich aussehen, geh doch mal bitte auf die Fragen von Hyperion ein.
Hi,
ja da habe ich noch ein ganzes stück Arbeit vor mir
So habe auf die Schnelle kurze verbesserungen durchgeführt, werde mich nach der
Mittagspause nochmal richtig ran setzten um den Mist fertig zu machen.
Hin und wieder nehme ich einen Print mit einem völlig Sinnlosen Wort drin, nur um zu sehen
ob der überhaupt den kram den er ausführen soll versucht
Dies ist der aktuelle Code "Brocken"
Dies ist eine der besagten .cfg Datein
Zur info: Das Nagios ist ein Testsystem nicht das Produktive
Vielen Dank schonmal im Vorraus
ja da habe ich noch ein ganzes stück Arbeit vor mir
So habe auf die Schnelle kurze verbesserungen durchgeführt, werde mich nach der
Mittagspause nochmal richtig ran setzten um den Mist fertig zu machen.
Hin und wieder nehme ich einen Print mit einem völlig Sinnlosen Wort drin, nur um zu sehen
ob der überhaupt den kram den er ausführen soll versucht
Code: Alles auswählen
import os
import re
pfad = '/usr/local/nagios/etc/objects/hosts/'
counter = 0
cfg =[]
for x in os.listdir(pfad):
if x.split(".")[1] =="cfg":
cfg.append(x)
c = 0
a = 1
while a == 1:
c = c + 1
try:
pfad2 = pfad + cfg[c]
# print(o)
if 'define host{' in open(pfad2).read():
for zeile in open(pfad2).read():
m = re.match(r"define host (})", zeile)
if m != None:
print(m.group ())
print(zeile)
except:
print("neu")
a = 0
Code: Alles auswählen
define host{
host_name UbuntuNagios
alias UbuntuNagios
check_command check-host-alive
parents Server 6
address 127.0.0.1
notification_options d,u,r
max_check_attempts 5
name UbuntuNagios
}
#define service{
# host_nam1e UbuntuNagios
# service_description check-disk-sda1
# check_command check_local_disk!20%!10%! /
# max_check_attempts 5
# check_interval 5
# retry_interval 3
# check_period 24x7
#}
#define service{
# host_nam1e UbuntuNagios
# service_description check-ping
# check_command check_ping!100.0,20%!500.0,60%
# max_check_attempts 5
# check_interval 1
# retry_interval 3
"host.cfg" [Nur Lesen] 33L, 718C
Zur info: Das Nagios ist ein Testsystem nicht das Produktive
Vielen Dank schonmal im Vorraus
@kimaro: Ich denke schon das man erst nach einer passenden Bibliothek sucht die das sicher besser macht als ein selbstgeschriebener, kruder Ad-Hoc ”Parser” ist schon eine lernenswerte Lektion.
Es ist nicht so einfach sich etwas robustes selber zu schreiben was dann auch tatsächlich mit allen möglichen und eigentlich gültigen Nagios-Konfigurationsdateien auch tatsächlich klar kommt.
Noch mal zum letzten Quelltext: Ob eine Zeichenkette mit einer bestimmten Zeichenkette endet kann man einfacher mit der `endswith()`-Methode testen. Die ganze Schleife liesse sich aber mit dem `glob`-Modul vermeiden.
Der Code ignoriert das erste Element in `cfg`. Da `os.listdir()` keine bestimmte Reihenfolge garantiert ignoriert man da also einen zufälligen Dateinamen. Das ist sicher nicht so gewollt. Und wie gesagt, man kann in Python *direkt* über die Elemente von Listen iterieren, ohne einen Umweg über einen Index.
Wenn Du das unbedingt selber schreiben wollst, dann müsstest Du systematisch beschreiben wie Du an den oder die gewünschten Werte aus so einer Datei heran kommst. Und als erstes vielleicht entscheiden ob Du die Datei nun komplett einlesen und als ganzes betrachten möchtest, oder die Zeilen der Datei einzeln. Der Mix den Du da versuchst funktioniert nicht.
Man könnte sich zum Beispiel die Zeilen der Reihe nach anschauen und sich merken ob man sich gerade in einem Host-Abschnitt befindet oder nicht. Und solange man in einem Abschnitt ist, die Zeile einer Ergebnisliste hinzufügen, und ansonsten ignorieren. Ungetestet:
Es ist nicht so einfach sich etwas robustes selber zu schreiben was dann auch tatsächlich mit allen möglichen und eigentlich gültigen Nagios-Konfigurationsdateien auch tatsächlich klar kommt.
Noch mal zum letzten Quelltext: Ob eine Zeichenkette mit einer bestimmten Zeichenkette endet kann man einfacher mit der `endswith()`-Methode testen. Die ganze Schleife liesse sich aber mit dem `glob`-Modul vermeiden.
Der Code ignoriert das erste Element in `cfg`. Da `os.listdir()` keine bestimmte Reihenfolge garantiert ignoriert man da also einen zufälligen Dateinamen. Das ist sicher nicht so gewollt. Und wie gesagt, man kann in Python *direkt* über die Elemente von Listen iterieren, ohne einen Umweg über einen Index.
Wenn Du das unbedingt selber schreiben wollst, dann müsstest Du systematisch beschreiben wie Du an den oder die gewünschten Werte aus so einer Datei heran kommst. Und als erstes vielleicht entscheiden ob Du die Datei nun komplett einlesen und als ganzes betrachten möchtest, oder die Zeilen der Datei einzeln. Der Mix den Du da versuchst funktioniert nicht.
Man könnte sich zum Beispiel die Zeilen der Reihe nach anschauen und sich merken ob man sich gerade in einem Host-Abschnitt befindet oder nicht. Und solange man in einem Abschnitt ist, die Zeile einer Ergebnisliste hinzufügen, und ansonsten ignorieren. Ungetestet:
Code: Alles auswählen
import os
from glob import iglob
from pprint import pprint
def extract_object(object_type, lines):
in_object = False
result = list()
start_marker = 'define {0}{{'.format(object_type)
for line in lines:
if line.startswith(start_marker):
in_object = True
if in_object:
result.append(line)
if line.lstrip().startswith('}'):
in_object = False
return result
def main():
base_path = '/usr/local/nagios/etc/objects/hosts/'
for filename in iglob(os.path.join(base_path, '*.cfg')):
with open(filename) as lines:
print('>', filename)
pprint(extract_object('host', lines))
if __name__ == '__main__':
main()
kann ich nicht einfach von der ersten "{" bis "}" etwas ausschneiden?
also die erste } im text suchen davon die Zeile ausgeben lassen und dann eben von Zeile 1 bis zur gesuchten Zeile den kram ausschneiden?
danke schon mal für die ausführliche Antwort
also die erste } im text suchen davon die Zeile ausgeben lassen und dann eben von Zeile 1 bis zur gesuchten Zeile den kram ausschneiden?
danke schon mal für die ausführliche Antwort
@kimaro: Jain, dann könntest Du auch versuchen einen regulären Ausdruck zu schreiben der meiner Funktion entspricht. Lesbarer und verständlicher wird es dadurch aber wohl nicht.
Zumal Du nicht einfach nach dem ersten '}' nach dem '{' suchen darfst, denn *innerhalb* eines Blocks kann das ja auch beliebig oft vorkommen. Du musst schon genau das '}' finden welches auch das Gegenstück zum '{' vom 'define host' ist. Und Du musst natürlich auch sicherstellen, dass das '{' zu einem 'define host' gehört *und* dass dieses nicht auskommentiert ist.
Sachen die für Menschen sehr einfach aussehen, können manchmal überraschend kompliziert formal zu beschreiben sein, so dass auch ein Rechner damit klar kommt.
Zumal Du nicht einfach nach dem ersten '}' nach dem '{' suchen darfst, denn *innerhalb* eines Blocks kann das ja auch beliebig oft vorkommen. Du musst schon genau das '}' finden welches auch das Gegenstück zum '{' vom 'define host' ist. Und Du musst natürlich auch sicherstellen, dass das '{' zu einem 'define host' gehört *und* dass dieses nicht auskommentiert ist.
Sachen die für Menschen sehr einfach aussehen, können manchmal überraschend kompliziert formal zu beschreiben sein, so dass auch ein Rechner damit klar kommt.