Python variable übergeben

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

Hallo, ich bin neu hier im forum und ich versuche mich gerade mal mit python.

Ich habe ein python script was mit autostart gestartet wird, dies funktioniert auch recht gut nur möchte ich jetzt ein shutdown script schreiben was vor dem shutdown den Prozess beendet. Ich habe im internet schon ein script gefunden was mir die pid id meines Prozesses ausliest und mit per print ausgibt. nun zu meiner Frage, wie kann ich diese ausgelesene pid id in mein shutdown script einfügen damit dieser beendet wird und danach der shutdown durchgeführt werden kann?

oder ist es irgendwie möglich direkt was in das shutdown script zu schreiben dieser mein Prozess killt ohne das pid id script? bin schon länger dran aber finde keine Lösung, ich hoffe ihr könnt mir da helfen.

hier mal das script um die id auszulesen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os,sys

def getPID(fotobox):
    cmd = "ps ax|grep -v grep | grep %s" % (fotobox)
    output = ""
    f=os.popen(cmd)
    for i in f.readlines():
        output = output + i
    if output == "":
        #-- Kein Prozess gefunden
        return("NOPID")
    else:
        #-- Prozess existiert, suche PID raus
        begin = 0
        y = True
        while y==True:
            if output[begin] == " ":
                # Leerzeichen gefunden, PID beginnt noch nicht
                begin += 1
            else:
                # Kein Leerzeichen gefunden, PID beginnt hier
                y = False
        end = begin
        y = True
        while y==True:
            if output[end] == " ":
                # Leerzeichen gefunden, PID endet hier, breche ab
                y= False
            else:
                end += 1
        return(output[begin:end])
try:
    searchfor = sys.argv[1]
except:
    print("USAGE: get.PID.py PROCESS")
    sys.exit(1)
print (getPID(searchfor))
und hier mein shutdown script:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os

#shutdown
os.system('sudo shutdown -a now')
danke euch Mit freundlichen Grüßen
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Was du da machst ist es so kompliziert dass man es besser sein lässt und jemand anderem die Arbeit überlässt. Praktischerweise hat jedes halbwegs moderne Betriebssystem hat ein Init System was dir sowas abnimmt, unter OS X launchd und unter Linux z.B. systemd. Windows hat da sicherlich auch eine brauchbare Lösung.
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

was ist denn das für eine Antwort? ich dachte für hilft und lerneffekte sind solche Foren da? wenn man nicht mal eine frage stellen kann ohne solche Sprüche zu bekommen, dass man es lieber anderen überlässt etc was sollen dann solche Foren? soll man sich übers wetter unterhalten? als ernsthaft jetzt. Ist nicht böse gemeint aber wie gesagt wenn man ein problem hat und dieser mit anderen teilen kann ist es nicht schön nur als Antwort zu bekommen das man es anderen überlassen soll!
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Es ist nicht sinnvoll irgendeine Antwort zu geben, sondern eine die zu einer richtigen und guten Lösung führt. Ich könnte dir jetzt eine Antwort geben die dir hilft deinen Ansatz weiterzuverfolgen aber du bist da nunmal auf einen Pfad geraten der nicht zu einer guten Lösung führt.

Um Hintergrundprozesse zu starten, zu beenden und grundsätzlich zu managen gibt es nunmal Init Systeme und bei modernen Init Systemen muss man Shutdown Skripte nicht mehr schreiben. Solche Shutdown Skripte überhaupt zu haben war schon immer eine schlechte Idee, dass es auch noch sehr schwer ist sowas richtig zu schreiben kommt dann noch erschwerend hinzu.

Das sowas schwer ist merkt man auch gleich an dem PID Skript was du gepostet hast. Dieses funktioniert nämlich nicht zuverlässig, was daran liegt dass man einfach nicht zuverlässig an die PID eines Prozesses über dessen Namen kommen kann. Der Hintergrundprozess selbst muss da kooperieren und eine Datei anlegen in der die PID steht. So einen Hintergrundprozess richtig zu schreiben ist übrigens auch sehr schwer, weswegen man ein Teil der Arbeit da auch an ein Init System übergibt. Darüberhinaus ist dieses PID Skript auch sehr schlecht geschrieben.

Es geht hier nicht darum dass du die Arbeit anderen überlassen sollst weil du dafür zu doof bist oder irgendwie sowas, sondern weil rein technisch sich dass ganze nur auf Ebene eines Init Systems wirklich zuverlässig und sicher umsetzen lässt.
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@fischi87: stell Dir Dein Skript vor, das Du aufrufen mußt um einen Shutdown richtig durchzuführen, und stell Dir ein zweites Skript vor, das genau das selbe verlangt. Dann kann nur eines von beiden sauber beendet werden.

Unter UNIXodalen Betriebssystemen ist es übrigens ganz einfach, eine Funktion aufzurufen, bevor ein Programm regulär, z.B. durch einen Shutdown, beendet wird:

Code: Alles auswählen

import signal
import sys

def quit(signum, frame):
    print "Terminated"
    sys.exit(0)
signal.signal(signal.SIGTERM, quit)
Aber wie schon DasIch geschrieben hat, hat jedes Betriebssystem einen Standardweg, wie man Dienste schreiben sollte. Entsprechend erwartet der Nutzer auch, dass man sich daran hält.

Entsprechend gibt es auch schon fertige Lösungen.

Auch wenn Dein Code nicht zielführend ist, ein paar Anmerkungen, was man technisch besser machen könnte:
Zeile 6: die Namenskonvention bei Funktionen ist wie bei Variablen, klein_mit_unterstrich, also get_pid. Die Funktion ist ja nicht auf eine fotobox-Anwendung beschränkt, also das Argument hätte besser process_name oder ähnlich geheißen.
Zeile 7/9: Du führst ein Commando in einer Shell aus, das auch noch einen beliebigen Text als Argument hinein formatiert. Gib dem Programm auch noch Systemrechte und Du hast ein schönes offenes Scheunentor. Daher folgende Regeln, niemals unkontrolliert Befehle an einem Shellaufruf übergeben. Shellaufrufe generell vermeiden, dieser grep-Aufruf könnte man einfach durch ein »if« direkt in Python realisieren. Drittens, keine externen Programm aufrufen, wenn es schon eine passende Bibliothek (psutil) dafür gibt. Die Klammern um fotobox sind überflüssig.
Zeile 9: statt os.popen besser die Funktionen aus subprocess benutzen
Zeile 10f: das ist eine umständliche Art »output = f.read()« zu schreiben.
Zeile 14: Fehler sollten nicht per magischem Rückgabewert sondern per Exception erfolgen
Zeile 14/34: return ist keine Funktion und sollte auch nicht wie eine geschrieben werden; die Klammern gehören weg.
Zeile 18/19/25: besser mit Endlos-Schleife und break arbeiten. y ist übrigens kein sehr aussagekräftiger Name.
Zeile 17-34: Python ist sehr mächtig, was Textbearbeitung betrifft. Die while-Schleifen könnte man durch .find ersetzen, das ganze durch »return output.split()[0]«

Also kurz:

Code: Alles auswählen

import psutil
def get_pid(process_name):
    return next(proc.pid for proc in psutil.process_iter() if proc.name() == process_name)
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

Vielen dank erstmal für die ausführliche antworten. Vielleicht sollte ich etwas genauer geklärten was ich vor habe.

Ich habe ein holzkiste mit Kamera etc. dies hat kein Tastatur sondern wird nur per Fernbedienung betrieben. ich wollte so ein script schreiben damit ich direkt nach dem drücken das Ausschalters auf der Fernbedienung erst alle laufenden Prozess beende bevor der shutdonw erfolgt. Ich könnte natürlich nur mittels dem shut down Befehl das system herunter fahren nur gibt es da ein kleiner problem. Ich hab noch led stripes dran hängen die leuchten wenn das system hochgefahren ist, wenn ich das system nun nur mit dem shutdown befehl herunterfahren bleiben die Leeds nur in der letzten Farbe stehen und schalten sich nicht aus, das war der ganze Hintergrund. ich wollte den led Prozess beenden und dann shutdown durchführen damit die Leds ausgeschalten werden.
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@fischi87: Falls Du die Lösung nicht entdeckt hast, hier nochmal in ausführlich:

Code: Alles auswählen

import signal

def quit(signum, frame):
    raise KeyboardInterrupt

def main():
    signal.signal(signal.SIGTERM, quit)

    try:
        led_an()
        while True:
            led_blink()
    except KeyboardInterrupt:
        pass
    finally:
        led_aus()

if __name__ == '__main__':
    main()
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

leider hast du recht, ich hab die Lösung nicht entdeckt da ich wie anfangs beschrieben gerade erst mit python anfange. ich werde dein Lösungsvorschläge später direkt prüfen. copy paste müsste also funktionieren oder muss ich in den code noch was ergänzen?

Mit freundlichen Grüßen

hab es gerade ausprobiert und bekomme diesen Fehler:


Traceback (most recent call last):
File "pid.py", line 19, in <module>
main()
File "pid.py", line 16, in main
led_aus()
NameError: global name 'led_aus' is not defined
BlackJack

@fischi87: Na dann hast Du wohl vergessen die Funktion zu schreiben. `led_an()` und `led_blink()` hast Du dann ja offensichtlich geschrieben, aber eben nicht `led_aus()`. Oder Du hast etwas an dem Quelltext verändert. Das können wir aber nicht wissen, deshalb ist es in der Regel sinnvoll den Quelltext zu dem Traceback zu zeigen.
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

sorry aber ist mir gerade zu hoch irgendwie. ich habe nix geschrieben von led an oder blick oder oder oder. woher nimmst du dieses?
BlackJack

@fischi87: Das nehme ich aus dem Quelltext von Sirius3. Du hast gesagt Du hast das ausprobiert, und das heisst für mich Du hast entweder den Quelltext von Sirius3 ausprobiert, oder Du hast da irgendwas ausprobiert was ausser Dir niemand kennt, weil Du es ja nicht gezeigt hast. Letztendlich ist aber klar das Du nicht den Quelltext von Sirius3 ausprobiert hast, denn der würde schon mit einem `NameError` für `led_an()` aussteigen, denn das wird ja auch nirgends definiert.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@fischi87: Der Code von Sirius3 zeigt Dir schon den korrekten Ansatz, funktioniert entgegen Deiner Annahme aber nicht per copy & paste. Wenn Du diesen kopierst, wirst Du bei der Ausführung einen Fehler erhalten, aber eben nicht den von Dir genannten "NameError: global name 'led_aus' is not defined", sondern einen anderen NameError. Daher die Frage von BlackJack, was Du denn geändert hast.

Dass Dir als Anfänger einige Dinge zu hoch sind ist völlig normal und nicht weiter schlimm. Und so zeigt Deine Frage, dass Du Funktionsaufrufe noch nicht als solche erkennst. Das sind Basics, um die Du Dich zuerst einmal kümmern solltest.

Copy & Paste von Programm-Schnipseln aus irgendwelchen Internetquellen ist übrigens eine ganz schlechte Idee; jedenfalls solange Du diesen Code nicht verstehen und bewerten kannst. Davon können Dir beispielsweise Wordpress-Anwender aus aller Welt, die lustig irgendwelche Themes und Plugins installieren, ein Lied singen.
fischi87
User
Beiträge: 6
Registriert: Donnerstag 7. Juli 2016, 20:09

okay vielen dank erstmal dafür. Ich merke schon ich werde mich wohl erstmal um basics bemühen den ich versteh gerade wirklich nur Bahnhof. ich danke euch trotzdem für eure zeit und vielleicht liest man sich mal wieder zu einem anderen Thema.

Mit freundlichen Grüßen
Antworten