System Unit Problem

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.
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Hallo zsammen,
Ich möchte ein Python Script per Systemd Starten.

Code: Alles auswählen

#!/usr/bin/python3
import os

path_to_file = os.environ['HOME'] + '/Pyapps/wire-py/wg_py.xml'
path_to_file = str(path_to_file)
a_connect = {}
file = open(path_to_file, 'r')
for line in file.readlines():
    line_splitted = line.split()
    a_connect[line_splitted[0]] = line_splitted[1]
    if 'true' in a_connect:
        auto_con = a_connect['true']
    else:
        pass
os.system('nmcli connection up ' + str(auto_con))


so steht es in einem python file was gemacht werden soll.

Dies ist die erste Meldung die kommt beim manuellen start des Unit.

Code: Alles auswählen

× wg_start.service - Automatic Tunnel Start
     Loaded: loaded (/usr/lib/systemd/system/wg_start.service; disabled; preset: enabled)
     Active: failed (Result: exit-code) since Sat 2024-09-07 16:04:58 CEST; 5s ago
    Process: 8078 ExecStartPre=/bin/sleep 3 (code=exited, status=0/SUCCESS)
    Process: 8082 ExecStart=/bin/start_wg.py (code=exited, status=1/FAILURE)
   Main PID: 8082 (code=exited, status=1/FAILURE)
        CPU: 431ms

Sep 07 16:04:54 asus systemd[1]: Starting wg_start.service - Automatic Tunnel Start...
Sep 07 16:04:57 asus start_wg.py[8082]: Traceback (most recent call last):
Sep 07 16:04:57 asus start_wg.py[8082]:   File "/bin/start_wg.py", line 4, in <module>
Sep 07 16:04:57 asus start_wg.py[8082]:     path_to_file = os.environ['HOME'] + '/Pyapps/wire-py/wg_py.xml'
Sep 07 16:04:57 asus start_wg.py[8082]:                    ~~~~~~~~~~^^^^^^^^
Sep 07 16:04:57 asus start_wg.py[8082]:   File "<frozen os>", line 685, in __getitem__
Sep 07 16:04:57 asus start_wg.py[8082]: KeyError: 'HOME'
Sep 07 16:04:58 asus systemd[1]: wg_start.service: Main process exited, code=exited, status=1/FAILURE
Sep 07 16:04:58 asus systemd[1]: wg_start.service: Failed with result 'exit-code'.
Sep 07 16:04:58 asus systemd[1]: Failed to start wg_start.service - Automatic Tunnel Start.
Geb ich in dem Pythonfile den kompletten Pfad an, also so path_to_file = /home/punix/Pyapps/wire-py/wg_py.xml'
funktioniert es. Ich brauch das aber so des der User ausgelesen wird.

Vielleicht hat einer ja ne Idde wie ich das lösen könnte.
Benutzeravatar
sparrow
User
Beiträge: 4527
Registriert: Freitag 17. April 2009, 10:28

Dein Gedankengang ist höchstwahrscheinlich falsch.
Was denkst du denn, als welcher Benutzer dein Programm ausgeführt wird? Und wie stellst du das sicher?
Grundsätzlich ist es mehr als ungewöhnlich ein Programm im Home-Verzeichnis zu verorten. Da gehört ein durch systemd geatarteter Service mit Sicherheit nicht hin.
Benutzeravatar
noisefloor
User
Beiträge: 4173
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Service Units laufen per Default unter `root` - und entsprechend sind die Umgebungsvariablen gesetzt. Wenn du Unit unter einem anderen Nutzer ausgeführt werden soll, dass musst du der Unit die Direktive `User=NUTZERNAME` mitgeben.

So wie das das os Modul benutzt ist das veraltet. Für Umgang mit Pfaden gibt es pathlib und das os.system veraltet ist steht sogar wörtlich in der Python-Doku. Stand der Dinge ist subprocess. Wenn du eine Datei öffnest, solltest du sie auch wieder schließen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/python3
from subprocess import check_call
from pathlib import Path

home = Path.home()
path_to_file = home / 'Pyapps' / 'wire-py' / 'wg_py.xml'
a_connect = {}
with open(path_to_file, 'r') as file:
for line in file.readlines():
    line_splitted = line.split()
    a_connect[line_splitted[0]] = line_splitted[1]
    if 'true' in a_connect:
        auto_con = a_connect['true']
check_call(['nmcli', 'connection',  'up', auto_con])
Wenn wg_py.xml eine XML Datei ist solltest du die mit einem XML-Parser lesen - Python hat ja einen an Bord - statt so wie du das machst.

Falls die Bedingung `if 'true' in a_connect` mal nicht zutreffen sollte crasht dein Skript in der letzten Zeile, weil dann `auto_con` nicht definiert ist.

Gruß, noisefloor

Gruß, noisefloor
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

sparrow hat geschrieben: Samstag 7. September 2024, 15:42 Dein Gedankengang ist höchstwahrscheinlich falsch.
Was denkst du denn, als welcher Benutzer dein Programm ausgeführt wird? Und wie stellst du das sicher?
Grundsätzlich ist es mehr als ungewöhnlich ein Programm im Home-Verzeichnis zu verorten. Da gehört ein durch systemd geatarteter Service mit Sicherheit nicht hin.
danke für deine Antwort.
Mir ist schon klar das das Programm als root ausgeführt wird.
und im Homverzeichnis befindet sich NUR die auszulesende Datei kein Skript oder Service.
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

noisefloor hat geschrieben: Samstag 7. September 2024, 15:42 Hallo,

Service Units laufen per Default unter `root` - und entsprechend sind die Umgebungsvariablen gesetzt. Wenn du Unit unter einem anderen Nutzer ausgeführt werden soll, dass musst du der Unit die Direktive `User=NUTZERNAME` mitgeben.

So wie das das os Modul benutzt ist das veraltet. Für Umgang mit Pfaden gibt es pathlib und das os.system veraltet ist steht sogar wörtlich in der Python-Doku. Stand der Dinge ist subprocess. Wenn du eine Datei öffnest, solltest du sie auch wieder schließen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/python3
from subprocess import check_call
from pathlib import Path

home = Path.home()
path_to_file = home / 'Pyapps' / 'wire-py' / 'wg_py.xml'
a_connect = {}
with open(path_to_file, 'r') as file:
for line in file.readlines():
    line_splitted = line.split()
    a_connect[line_splitted[0]] = line_splitted[1]
    if 'true' in a_connect:
        auto_con = a_connect['true']
check_call(['nmcli', 'connection',  'up', auto_con])
Wenn wg_py.xml eine XML Datei ist solltest du die mit einem XML-Parser lesen - Python hat ja einen an Bord - statt so wie du das machst.

Falls die Bedingung `if 'true' in a_connect` mal nicht zutreffen sollte crasht dein Skript in der letzten Zeile, weil dann `auto_con` nicht definiert ist.

Gruß, noisefloor

Gruß, noisefloor
Vielen dank! für die Hinweise!
close hatte ich übersehn hab es aus meinem Hauptprogram rauskopiert mir ging es nur darum den Start zu testen.
nur im Hauptprogramm brauch ich das so.
Da ohnehin nur eine Zeile in der Datei steht werd ich das anders machen z.b als Liste.
Zur If abfrage: das kommt auch noch dran. Daran hab ich schon gedacht.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1224
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Hier mal ein Anfang.
Es lohnt sich auch, das Tutorial durchzuarbeiten: https://docs.python.org/3/library/xml.e ... l#tutorial

Code: Alles auswählen

#!/usr/bin/python3
import xml.etree.ElementTree as ET

from pathlib import Path


def open_xml(path):
    doc = ET.parse(path)
    return doc.getroot()


def xml2dict(xml_root):
    """
    Implementieurng um die entsprechenden Daten aus dem XML-Dokument zu bekommen
    """
    return {}


if __name__ == "__main__":
    # xml_file = Path.home() / "Pyapps/wire-py/wg_py.xml"
    xml_file = Path("/usr/share/metainfo/org.kde.plasma.systemmonitor.net.appdata.xml")

    if not path.exists():
        raise RuntimeError(f"Could not find {path}")

    root = open_xml(xml_file)
    # data = xml2dict(root)

    # man kann über Elemente iterieren
    for element in root:
        print(f"TAG: {element.tag} | Text: {element.text} | Attributes: {element.attrib}")
        # TAG: summary | Text: 显示下载和上传速率的系统监视挂件 | Attributes: {'{http://www.w3.org/XML/1998/namespace}lang': 'zh_CN'}


    # man kann aber auch im XML-Baum suchen
    for summary in root.findall(".//summary"):
        print(summary.text)
        
    # root ist auch element
    print(root)

    # https://docs.python.org/3/library/xml.etree.elementtree.html#tutorial

sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

DeaD_EyE hat geschrieben: Sonntag 8. September 2024, 08:42 Hier mal ein Anfang.
Es lohnt sich auch, das Tutorial durchzuarbeiten: https://docs.python.org/3/library/xml.e ... l#tutorial

Code: Alles auswählen

#!/usr/bin/python3
import xml.etree.ElementTree as ET

from pathlib import Path


def open_xml(path):
    doc = ET.parse(path)
    return doc.getroot()


def xml2dict(xml_root):
    """
    Implementieurng um die entsprechenden Daten aus dem XML-Dokument zu bekommen
    """
    return {}


if __name__ == "__main__":
    # xml_file = Path.home() / "Pyapps/wire-py/wg_py.xml"
    xml_file = Path("/usr/share/metainfo/org.kde.plasma.systemmonitor.net.appdata.xml")

    if not path.exists():
        raise RuntimeError(f"Could not find {path}")

    root = open_xml(xml_file)
    # data = xml2dict(root)

    # man kann über Elemente iterieren
    for element in root:
        print(f"TAG: {element.tag} | Text: {element.text} | Attributes: {element.attrib}")
        # TAG: summary | Text: 显示下载和上传速率的系统监视挂件 | Attributes: {'{http://www.w3.org/XML/1998/namespace}lang': 'zh_CN'}


    # man kann aber auch im XML-Baum suchen
    for summary in root.findall(".//summary"):
        print(summary.text)
        
    # root ist auch element
    print(root)

    # https://docs.python.org/3/library/xml.etree.elementtree.html#tutorial

Dankeschön werd ich mir anschauen.
Benutzeravatar
noisefloor
User
Beiträge: 4173
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@punix: wenn du auf einen Beitrag unmittelbar antwortest lass' bitte das Volltextzitat weg. a) brauchst du den Text, der direkt davor im Post steht nicht nochmal wiederholen, b) erhöhst du die Chancen, dass keine kurze Antwort einfach untergeht.

Gruß, noisefloor
Benutzeravatar
sparrow
User
Beiträge: 4527
Registriert: Freitag 17. April 2009, 10:28

punix hat geschrieben: Samstag 7. September 2024, 16:39 Mir ist schon klar das das Programm als root ausgeführt wird.
und im Homverzeichnis befindet sich NUR die auszulesende Datei kein Skript oder Service.
Das widerspricht sich.
Wenn du weißt, dass das Programm als root ausgeführt wird, wieso denkst du dann, dass die HOME Umgebungsvariable auf das Heimatverzeichnis eines beliebigen Benutzers zeigt?

Wenn die auszulesede Datei Konfigurationseinseinstellungen enthält, gibt es auch dafür den richtigen Platz in Verzeichnisbaum. Wenn /etc vom System verwaltet wird, könnte man /opt ins Auge fassen iirc
Benutzeravatar
noisefloor
User
Beiträge: 4173
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Ergänzend dazu: Der Nutzer `Root` hat unter Debian-basierten Distro inkl. Ubuntu und Raspberry Pi OS ein Homeverzeichnis, nämlich `/root`. Nur ist das halt per Default leer.

Gruß, noisefloor
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

In /opt brauch ich auch root rechte um darin zu schreiben.
Dies möchte ich vermeiden.
Meine py_wg.xml hab ich jetzt umbenannt. Wird jetzt ohne Dateiendung verwendet da ohnehin immer nur ein eintrag drin steht. Und dank des hinweis mit subprocess,
hab ich jetzt auch im kompletten Programm os.system durch check_call ersetzt.
Wollt ich erst später machen... Da erstmal das Programm ansich funktionieren sollte bevor ich solche änderungen mach.
Ich werd das so machen das bei der installation von dem Startscript der absolute pfad vom user eingetragen wird.
nezzcarth
User
Beiträge: 1749
Registriert: Samstag 16. April 2011, 12:47

punix hat geschrieben: Sonntag 8. September 2024, 19:26 In /opt brauch ich auch root rechte um darin zu schreiben.
Dies möchte ich vermeiden.
Skripte, die global über Systemd ausgeführt werden, haben aber in irgendwelchen User-Ordnern nichts verloren. Die sollten zentral abgelegt werden. Meine Faustregel ist: Größere Software-Pakete, die am Paketmanager vorbei installiert werden, gehören nach /opt, einzelne Skripte wie in deinem Fall, nach /usr/local/bin. Beide Ordner sind genau für solche Zwecke gedacht; für Details siehe FHS Kapitel 3.13 und 4.9. Dass du root-Rechte brauchst, um darin zu schreiben, ist richtig. Das ist in dem Fall aber nicht schlimm. Die Ordner sind dafür da, dass der Admin Sachen vom OS unbehelligt installieren kann, und das ist genau, was du tust. Das heißt ja nicht, dass man root sein muss, um sie auszuführen.
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Das Skript ist ja auch nicht im homeverzeichnis.
Das kommt dann entweder in /opt oder /usr
Im wesentlichen ging es mir darum einen Befehl auszuführen bei dem man sonst auch keine rootrechte braucht. Im homverzeichnis liegt nur eine Textdatei in der gekuckt wird was drin steht.
Steht in der Datei true dann soll der Befehl wie in Skript in z.b /opt ausgeführt werden.
Wenn false dann mach nichts.
Liegt diese Datei in /opt oder in /usr, werden rootrechte zum öffnen gebraucht.
Dies kann man auf verschiedene Arten lösen.
Fürs erste werd ich es so machen.
Da gibts bestimmt bessere lösungen.
Ich kann natürlich nur von meinem Kenntnisstand ausgehen. Bin ja am Python lernen :-)
Wenn ich hier den kompletten codem hochladen würde, denkt sich der eine oder andere bestimmt was des für Müll..... Bisher macht mein Programm das was es soll und so wie ich es möchte.

Code: Alles auswählen

#!/usr/bin/python3
import os
from pathlib import Path
import subprocess
from getpass import getpass

startfile = ['#!/usr/bin/python3',
             'from subprocess import check_call', '\n',

             'path_to_file = ', '\n',

             'with open(path_to_file, 'r') as file:',
             '    for line in file.readlines():    ',
             '        a_con = line[5:]             ',
             "check_call(['nmcli', 'connection', 'up', a_con])",
             'file.close()']
home = Path.home()
# for services file in /lib/systemd/system/
path_for_a_con = home / '.config/wire_py/wg_py'
# replace in startfile
startfile[3] = 'path_to_file = ' "'" + str(path_for_a_con) + "'"

with open('start_wg.py', 'w') as file_for_a_con:
    for line in startfile:
        file_for_a_con.write(line + '\n')
file_for_a_con.close()

# create dir in home
mkdir = home / '.config/wire_py'
os.makedirs(mkdir, exist_ok=True)

with open(mkdir / 'wg_py', 'w+') as file:
    if 'true' not in file:
        file.write('false')
file.close()

# Prompt the user for the sudo password
sudo_password = getpass('Enter sudo password: ')
#def cp_files():

# Define the command to run the Python script with sudo
#command = ['sudo', '-S', 'python3', 'script.py']

# Run the command as a subprocess, passing the sudo password
#subprocess.run(command, input=sudo_password.encode(), check=True)

Sirius3
User
Beiträge: 18252
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei with braucht man kein close und wenn Du pathlib benutzt, brauchst Du kein os.
Statt eine Liste nachträglich zu ändern erzeugt man den String gleich so, wie Du ihn brauchst.
Strings stückelt man nicht mit + zusammen.
`mkdir` ist der Name einer Funktion, das für ein Path-Objekt zu benutzen, ist sehr verwirrend.
Warum erzeugst Du aber nochmal den selben Pfad, der ja schon in `path_for_a_con` steht?
Der Dateimodus w+ ist selten sinnvoll. Was beim if tatsächlich gelesen und was wo dann das write in der Datei landet, ist undurchsichtig, Man würde das in zwei Schritten machen.
Normalerweise enden alle Zeilen einer Text-Datei mit einem Zeileendezeichen, das fehlt bei Deinem Test, so dass der Inhalt schon sehr speziell sein muß, damit die if-Abfrage nicht erfüllt ist.
Magische Werte sollte man nicht benutzen, warum gerade die 5 bei line[5:]?

Code: Alles auswählen

#!/usr/bin/python3
from pathlib import Path
import subprocess

CONFIG_PATH = Path.home() / ".config" / "wire_py" / "wg_py"

START_FILE = f'''\
#!/usr/bin/python3',
from subprocess import check_call


path_to_file = {str(CONFIG_PATH)!r}


with open(path_to_file, 'r') as file:
    *_, last_line = file
connection_id = line[5:]
check_call(['nmcli', 'connection', 'up', connection_id])
'''

Path("start_wg.py").write_text(START_FILE)

CONFIG_PATH.parent.mkdir(exit_ok=True)
if CONFIG_PATH.read_text() != "true":
    CONFIG_PATH.write_text("false")
Konfigurationsdateien sollte, wie schon mehrfach geschrieben in /etc liegen.
Es ist ungewöhnlich, ein Python-Programm zu haben, das ein Python-Programm erzeugt, weil man könnte das Pythonprogramm ja direkt schreiben, vor allem, wenn man das mit der Config-Datei richtig macht.
Wobei ich das komplett ohne Python lösen würde, da ja eh nur ein Programm gestartet werden soll

Code: Alles auswählen

nmcli connection up $(</etc/wg_py)
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Dankeschön für die Hinweise!
line[:5] damit wird true weg geschnitten was in der Datei steht.
true irgendebbes wird zu irgendebbes.
Sirius3
User
Beiträge: 18252
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum steht dann "true irgendebbes" in der Datei, wenn nur "irgendebbes" relevant ist?
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Code: Alles auswählen

class OnOff(tk.Tk, FileHandle):
    def __init__(self, container, **kwargs):
        super().__init__(container, **kwargs)
        self.lb_frame_buttons = None

    def on_off(self):
        with open(path_to_file, 'r') as file:
            for line in file.readlines():
                a_connect = line
            if 'true' in a_connect:
                self.selected_option.set(1)
                self.autoconnect_var.set('')
                self.auto_con = a_connect[5:]
            else:
                self.wg_autostart.configure(state='disabled')
                self.auto_con = 'no Autoconnect'
        file.close()

        self.autoconnect_var = tk.StringVar()
        self.autoconnect_var.set(self.auto_con)
        self.autoconnect = tk.Label(self, textvariable=self.autoconnect_var, fg='blue', padx=5)
        self.autoconnect.config(font=('Ubuntu', 11))
        self.autoconnect.grid(column=0, row=4, sticky='ne', pady=20)
Bei def on_off(self)
hab ich das rein
Da es anders nicht funktioniert hat.
Z.b Abfrage ob Datei leer ist.
Weder mit a_connect != ' '
Noch mit len(aconnect) != 0
Was vielleicht geht ist ja fragen ob die Datei da ist.
Daran hab ich bisher noch nicht gedacht.
Sirius3
User
Beiträge: 18252
Registriert: Sonntag 21. Oktober 2012, 17:20

with schließt die Datei automatisch. Das close ist unnötig.
Der Code beschreibt, dass Du nur die letzte Zeile der Datei betrachtest. Wenn die Datei aber nur eine Zeile enthält, ist das Konstrukt, das Du da benutzt, verwirrend.
`in` prüft, ob der String irgendwo in der letzten Zeile vorkommt. Anscheinend möchtest Du aber prüfen, ob der String mit "true" startet.
Wenn es nur um die Prüfung geht, ob ein Wert gesetzt ist, oder nicht, dann ist das einfachere, entweder eine leere Datei abzulegen, oder gar keine Datei.

Code: Alles auswählen

connection_id = path_to_file.read_text().strip()
if not connection_id: ...
Warum erbt OnOff von FileHandle?
In __init__ sollten alle Attribute angelegt werden, in anderen Methoden werden nur noch die Werte existierender Attribute geändert.
Vor allem legt man keine neuen Widgets an, weil diese ja dann vorhandene überlagern, und so immer mehr werden.
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Sorry close hatte ich über sehen.
Da ich die Attribute hier mit drin hab dacht ich lass die Klasse hiervon erben.
Vielleicht schmeis ich die aber auch zusammen.

Code: Alles auswählen

class FileHandle:

    def __init__(self):

        self.wg_autostart = None
        self.autoconnect = None
        self.auto_con = None
        self.autoconnect_var = None
        self.tl = None
        self.selected_option = None
        self.l_box = None
        self.select_tunnel = None

    def box_set(self):
        try:
            self.select_tunnel = self.l_box.curselection()
            select_tl = self.l_box.get(self.select_tunnel[0])
            if self.selected_option.get() == 0:
                off = open(path_to_file, 'w')
                off.write('false ' + '\n')
                off.close()
                tl = ListTunnels.tl_list()
                if len(tl) == 0:
                    self.wg_autostart.configure(state='disabled')
            if self.selected_option.get() >= 1:
                set_on = open(path_to_file, 'w')
                set_on.write('true ' + select_tl)
                set_on.close()

        except IndexError:
            self.selected_option.set(1)

        OnOff.on_off(self)


class OnOff(tk.Tk, FileHandle):
    def __init__(self, container, **kwargs):
        super().__init__(container, **kwargs)
        self.lb_frame_buttons = None

    def on_off(self):
        with open(path_to_file, 'r') as file:
            for line in file.readlines():
                a_connect = line
            if 'true' in a_connect:
                self.selected_option.set(1)
                self.autoconnect_var.set('')
                self.auto_con = a_connect[5:]
            else:
                self.wg_autostart.configure(state='disabled')
                self.auto_con = 'no Autoconnect'
        file.close()

        self.autoconnect_var = tk.StringVar()
        self.autoconnect_var.set(self.auto_con)
        self.autoconnect = tk.Label(self, textvariable=self.autoconnect_var, fg='blue', padx=5)
        self.autoconnect.config(font=('Ubuntu', 11))
        self.autoconnect.grid(column=0, row=4, sticky='ne', pady=20)
punix
User
Beiträge: 18
Registriert: Montag 3. April 2023, 11:34

Sirius3 hat geschrieben: Dienstag 10. September 2024, 20:53 Bei with braucht man kein close und wenn Du pathlib benutzt, brauchst Du kein os.
Statt eine Liste nachträglich zu ändern erzeugt man den String gleich so, wie Du ihn brauchst.
Strings stückelt man nicht mit + zusammen.
`mkdir` ist der Name einer Funktion, das für ein Path-Objekt zu benutzen, ist sehr verwirrend.
Warum erzeugst Du aber nochmal den selben Pfad, der ja schon in `path_for_a_con` steht?
Der Dateimodus w+ ist selten sinnvoll. Was beim if tatsächlich gelesen und was wo dann das write in der Datei landet, ist undurchsichtig, Man würde das in zwei Schritten machen.
Normalerweise enden alle Zeilen einer Text-Datei mit einem Zeileendezeichen, das fehlt bei Deinem Test, so dass der Inhalt schon sehr speziell sein muß, damit die if-Abfrage nicht erfüllt ist.
Magische Werte sollte man nicht benutzen, warum gerade die 5 bei line[5:]?

Code: Alles auswählen

#!/usr/bin/python3
from pathlib import Path
import subprocess

CONFIG_PATH = Path.home() / ".config" / "wire_py" / "wg_py"

START_FILE = f'''\
#!/usr/bin/python3',
from subprocess import check_call


path_to_file = {str(CONFIG_PATH)!r}


with open(path_to_file, 'r') as file:
    *_, last_line = file
connection_id = line[5:]
check_call(['nmcli', 'connection', 'up', connection_id])
'''

Path("start_wg.py").write_text(START_FILE)

CONFIG_PATH.parent.mkdir(exit_ok=True)
if CONFIG_PATH.read_text() != "true":
    CONFIG_PATH.write_text("false")
Konfigurationsdateien sollte, wie schon mehrfach geschrieben in /etc liegen.
Es ist ungewöhnlich, ein Python-Programm zu haben, das ein Python-Programm erzeugt, weil man könnte das Pythonprogramm ja direkt schreiben, vor allem, wenn man das mit der Config-Datei richtig macht.
Wobei ich das komplett ohne Python lösen würde, da ja eh nur ein Programm gestartet werden soll

Code: Alles auswählen

nmcli connection up $(</etc/wg_py)
Dankeschon nochmal Sirius3! war sehr hilfreich hab es jetzt umgesetzt dein vorschlag. etwas korrigiert und funktioniert.
So ist es deutlich kürzer das ganze. Vorgestern hatte ich genau danach gesucht nur nicht in pathlib :-). Das Modul muss ich mir
auf jeden Fall anschauen.
Antworten