Stringbearbeitung und subprocess

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Mittwoch 30. März 2011, 10:52

Hallo,

ich möchte ein kleines Programm schreiben, welches über SSH eine Abfrage startet und mir die installierten Xen-VMs ausgibt. Das ist mein Sourcecode:

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-

import subprocess

hosts = ( 
    'xen01',
    'xen02',
    'xen03',
    'xen05'
)

def get_vmlist():
    host_out = []
    for i in range(0, len(hosts)):
        output = subprocess.Popen(['ssh','-l','root',str(hosts[i]),'xe','vm-list|grep','name-label'], stdout=subprocess.PIPE)
        host_out.append(output.stdout.read())
    return host_out

vms = get_vmlist()
print vms[0]
Die Ausgabe von vms[0] sieht dann so aus:
name-label ( RW): CAG1
name-label ( RW): CLS01
name-label ( RW): Mail-3
name-label ( RW): RSA01
name-label ( RW): Control domain on host: xen01
name-label ( RW): Web01
name-label ( RW): Monitoring01
name-label ( RW): MX1
name-label ( RW): Mail-1
Wie man unschwer erkennen kann, bekomme ich neben dem Rechnernamen noch einige überflüssige Informationen, die ich gerne wegfiltern möchte.

Habt ihr eine Idee wie das anstellen kann? Kann ich die Ausgabe von subprocess.Popen auch zeilenweise in eine Liste schreiben? Das würde die Sache glaube ich vereinfachen.
BlackJack

Mittwoch 30. März 2011, 11:22

@peddy: Dateiobjekte sind "iterable" und zwar sind sie Iteratoren über die Zeilen. Also kann man eine Liste mit Zeilen ganz einfach mit der `list()`-Funktion bekommen.

Bitte werde das `i` in der Schleife los. Das und der `str()`-Aufruf auf das jeweilige `hosts`-Element sind beide total überflüssig. Man kann bei den Sequenztypen in Python *direkt* über die Elemente iterieren und muss keinen Umweg über einen Index machen. Also ``for host in hosts:``…

Ansonsten sieht mir das wirklich nach grundlegender Zeichenkettenverarbeitung aus. Schau doch einfach mal was Zeichenketten so an Methoden und Indexmöglichkeiten (Stichwort "slicing") bieten.
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Mittwoch 30. März 2011, 12:59

Danke für deine Denkanstöße, dass hat mich einen guten Schritt weiter gebracht. Ich habe mein Script überdacht und etwas umgebaut. Mein Programm wird dadurch hoffentlich etwas flexibler und schöner lesbar.

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-

import subprocess

hosts = (
    'xen01',
    'xen02',
    'xen03',
    'xen05'
)

def get_vms(hostname):
    output = subprocess.Popen(['ssh','-l','root',hostname,'xe','vm-list|grep','name-label'], stdout=subprocess.PIPE)
    vm_liste = output.stdout.read()
    return vm_liste

for hostname in hosts:
    print get_vms(hostname)
Ich blicke jedoch noch nicht, wie ich die Ausgabe zeilenweise in eine Liste schreiben kann. print list(get_vms(hostname)) liefert mir so was:
[' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'C', 'A', 'G', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'C', 'L', 'S', '0', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'M', 'a', 'i', 'l', '-', '3', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'R', 'S', 'A', '0', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'C', 'o', 'n', 't', 'r', 'o', 'l', ' ', 'd', 'o', 'm', 'a', 'i', 'n', ' ', 'o', 'n', ' ', 'h', 'o', 's', 't', ':', ' ', 'x', 'e', 'n', '0', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'W', 'e', 'b', '0', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'M', 'o', 'n', 'i', 't', 'o', 'r', 'i', 'n', 'g', '0', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'M', 'X', '1', '\n', ' ', ' ', ' ', ' ', ' ', 'n', 'a', 'm', 'e', '-', 'l', 'a', 'b', 'e', 'l', ' ', '(', ' ', 'R', 'W', ')', ':', ' ', 'M', 'a', 'i', 'l', '-', '1', '\n']
EyDu
User
Beiträge: 4872
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mittwoch 30. März 2011, 13:05

Suchst du

Code: Alles auswählen

print get_vms(hostname).split("\n")
?
Das Leben ist wie ein Tennisball.
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Mittwoch 30. März 2011, 13:14

EyDu hat geschrieben:Suchst du

Code: Alles auswählen

print get_vms(hostname).split("\n")
?
Danke, das geht.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Mittwoch 30. März 2011, 13:38

Code: Alles auswählen

>>> "hallo\nwelt".splitlines()
['hallo', 'welt']
finde ich da noch etwas schoener.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Donnerstag 31. März 2011, 12:50

Hallo,

könnt ihr mal meinen Code überfliegen und mir sagen was ein Profi optimieren würde?

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-

import subprocess

hosts = (
    'xen01',
    'xen02',
    'xen03',
    'xen05'
)

def get_vms(hostname):
    vm_liste = []
    output = subprocess.Popen(['ssh','-l','root',hostname,'xe','vm-list|grep','name-label'], stdout=subprocess.PIPE)
    vms_unformatiert = output.stdout.read()
    for line in vms_unformatiert.splitlines():
        if hostname not in line:
            vm_liste.append(line.replace('name-label ( RW):','').strip())
    return vm_liste

for host in hosts:
    print get_vms(host)
Output:
['CAG1', 'CLS01', 'Mail-3', 'RSA01', 'Web01', 'Monitoring01', 'MX1', 'Mail-1']
['FTPS01', 'DC02', 'RSA02', 'PS3', 'CLS02', 'MX2', 'Mail-2', 'SQL04']
...
...
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Donnerstag 31. März 2011, 13:00

So hab jetzt selber noch ein paar Sachen gefunden:

Code: Alles auswählen

def get_vms(hostname):
    vm_liste = []
    output = subprocess.Popen(['ssh','-l','root',hostname,'xe','vm-list|grep','name-label'], stdout=subprocess.PIPE)
    for line in output.stdout.read().splitlines():
        if hostname not in line:
            vm_liste.append(line.replace('name-label ( RW):','').strip())
    return vm_liste
deets

Donnerstag 31. März 2011, 13:04

peddy hat geschrieben:Hallo,

könnt ihr mal meinen Code überfliegen und mir sagen was ein Profi optimieren würde?
Ich wuerde noch ein

Code: Alles auswählen

# achtung, aussem kopp, schau nochmal in die doku
stdout, strerr = output.communicate()
reinwerfen. Und die variable dann auch nicht output nennen.

Der Grund ist, dass du sonst in eine race-condition kommen kannst. Wenn zB aufgrund von Netzwerk-Problemen der Aufbau der Verbindung verzoegert wird, dann liest dein Programm nix ein, und macht froehlich weiter. Daher solltest du auf jeden Fall auf's Ende des Prozesses warten.

Und im Grunde natuerlich auch noch Fehlerbehandlung betreiben...
BlackJack

Donnerstag 31. März 2011, 13:12

@peddy: Dateien sind wie schon gesagt "iterable". Und zwar liefern sie die Zeilen in der Datei eine nach der anderen. Es ist also unnötig die Daten von `output.stdout` erst komplett zu lesen und dann in Zeilen aufzuteilen.

@deets: Die race condition sehe ich nicht!? Das lesen hört doch erst auf wenn die Gegenseite Datei geschlossen hat, nicht wenn es blockiert weil die Gegenseite noch nichts geschrieben hat.
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Donnerstag 31. März 2011, 13:52

BlackJack hat geschrieben:@peddy: Dateien sind wie schon gesagt "iterable". Und zwar liefern sie die Zeilen in der Datei eine nach der anderen. Es ist also unnötig die Daten von `output.stdout` erst komplett zu lesen und dann in Zeilen aufzuteilen.
Ich glaube zu wissen was du meinst, aber ich kann es nicht umsetzten. Kannst du mir noch einen Tipp geben, wie die Syntax aussehen müsste?
BlackJack

Donnerstag 31. März 2011, 13:58

@peddy: ``for line in output.stdout:``
deets

Donnerstag 31. März 2011, 19:53

BlackJack hat geschrieben: @deets: Die race condition sehe ich nicht!? Das lesen hört doch erst auf wenn die Gegenseite Datei geschlossen hat, nicht wenn es blockiert weil die Gegenseite noch nichts geschrieben hat.
Wo du recht hast.. Ich nehme alles zurueck und behaupte das Gegenteil!
Antworten