Python möchte ich nicht mehr missen. Gerade wenn man Scripts zur Systemadministration und Systemdokumentation schreibt, bei denen das mit einem Shell-Script kompliziert wird, ist das eine sehr praktische und dennoch erfreulich übersichtliche (und somit sehr gut wartbare) Sprache. Auch die Möglichkeit, jedes Statement einzeln schon mal vorher in der Python-Konsole ausprobieren zu können, macht mir das Leben doch viel einfacher.
LEGACY PYTHON
Python 2.7 wird nur noch bis
Februar 2020
mit Sicherheitsupdates versorgt
→Python Release Cycle
Vorbemerkung: Auf dieser Seite ist alles etwas veraltet in Python Version 2 geschrieben. Heute sollte man lieber Python3 verwenden, wenn es keinen sehr guten Grund dagegen gibt1).
Siehe auch: Python3 Spickzettel
von der Konsole aus:
$ python -V
interaktiv / Script:
import sys
print sys.version
die Python-Konsole lässt sich prima als Taschenrechner missbrauchen …
def mw(netto): mw=netto*0.19+netto return mw
Und so sieht das auf der Konsole aus:
heb@moorbirke:~/bin> python Python 2.5 (r25:51908, Jan 9 2007, 16:59:32) [GCC 4.1.2 20061115 (prerelease) (some Linux)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> def mw(netto): ... mw=netto*0.19+netto ... return mw ... >>> >>> mw(100) 119.0 >>>
und für schnödes Glücksspiel kann man Python auch einsetzen:
#!/usr/bin/env python import random seiten=(1,2,3,4,5,6) print random.choice (seiten)
IP="192.168.5.55" PORT="80" DNSname="www.example.com" HWname="lnx-kluftinger"
Dreimal die selbe Ausgabe auf 3 verschiedenen Arten
print "* " + IP + ":" + PORT + " -- " + DNSname + " -- " + HWname print "* %(a)s:%(b)s -- %(c)s -- %(d)s" % {'a':IP,'b': PORT, 'c': DNSname, 'd':HWname} print "* %s:%s -- %s -- %s" % ( IP, PORT, DNSname, HWname )
Ausgabe:
* 192.168.5.55:80 -- www.example.com -- lnx-kluftinger
Deutlich mehr Varianten für formatierten Text gibt es mit Python3
#!/usr/bin/env python # test-mysql-db.py import MySQLdb dbhost="testdb.example.com" dbuser="testuser" dbpasswd="strenggeheim" dbname="testdb" def mysqldbquery(dbq): # verbindung zum datenbankserver aufnehmen try: db = MySQLdb.connect (host=dbserver,user=dbuser, passwd=dbpasswd, db=dbname) except MySQLdb.OperationalError: # wenn das mit der DB-Verbindung nicht klappt, Fehlermeldung print "Fehler beim Verbinden mit Datenbank %s: %s " % (dbserver,sys.exc_info()[1]) cursor = db.cursor() cursor.execute(dbq) result = cursor.fetchone() # hole nur eine zeile, wenn man alle will: fetchall() if (not (result)): result=('') # diese fehlerbehandlung koennte noch leicht optimiert werden ... db.close() return result if __name__ == '__main__': ergebnis=mysqldbquery("select Servername from ServerTable where ServerIP='192.168.192.168'") print ergebnis[0]
vorsicht, ungetestetes Fragment :
import pg dbserver="testpg.example.com" dbuser="testuser" dbpasswd="strenggeheim" datenbankname="testdb" # verbindung zum datenbankserver aufnehmen def pgdbquery(dbq) try: pgcon = pg.connect( dbname=datenbankname, host=dbserver, user=dbuser, passwd=dbpasswd) except pg.InternalError: print "Fehler beim Verbinden mit %s: %s " % (dbserver,sys.exc_info()[1]) resulttuplelist=pgcon.query(dbq).getresult() # hole alles pg.close return resulttuplelist
für Python 2.3 und niedriger (ohne Warnungen auch mit 2.4 und 2.5)
#!/usr/bin/env python # test-ssh.py import os # python <= 2.5 def sshcmd(server,cmd): """sshcmd(server,cmd) -> string connect via ssh to server, do command cmd on that server, return max 900 characters of output to stdout """ cmdsum= "ssh -o ConnectTimeout=5 %s %s" % (server,cmd) myin,myout,myerr=os.popen3(cmdsum) # python <= 2.5 txt=myout.read(900) myerror=myerr.read(800) # FIXME if(myerror): txt="ERROR: (ssh to %s): %s " % (server,myerror) return txt if __name__ == '__main__': print sshcmd("192.168.192.168","uname")
ab Python 2.6 erhält man bei obigen Script die Warnung "os.popen3 is deprecated. Use the subprocess module".
Deswegen sollte man die popen3-Zeile jetzt ein wenig anders (leider etwas umständlicher) ausdrücken:
#!/usr/bin/env python # test-ssh.py import subprocess # python => 2.4 def sshcmd(server,cmd): """sshcmd(server,cmd) -> string connect via ssh to server, do command cmd on that server, return max 900 characters of output to stdout """ cmdsum= "ssh -o ConnectTimeout=5 %s %s" % (server,cmd) # v-- python => 2.4 p = subprocess.Popen(cmdsum, shell=True,bufsize=0, stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,close_fds=True) myin,myout,myerr=(p.stdin,p.stdout,p.stderr) # ^-- python => 2.4 txt=myout.read(900) myerror=myerr.read(800) # FIXME if(myerror): txt="ERROR: (ssh to %s): %s " % (server,myerror) return txt if __name__ == '__main__': print sshcmd("192.168.192.168","uname")
Das Modul subprocess
gibt es seit Python 2.4
#!/usr/bin/env python # test-ssh.2.py import os def sshcmderr(server,cmd): """sshcmd(server,cmd) -> string connect via ssh to server, do command cmd on that server, return output and error in tupple """ cmdsum= "ssh -o ConnectTimeout=5 %s %s" % (server,cmd) myin,myout,myerr=os.popen3(cmdsum) # python <= 2.5 txt=myout.read(9999) myerror=myerr.read(9999) return(txt,myerror) if __name__ == '__main__': ausgabe,fehler=sshcmd("192.168.192.168","uname") print ausgabe print fehler
Krankes Konstrukt, um auf einem entfernten Rechner einzelne Dateien mit egrep zu durchsuchen … (die Suchstrings werden als Aufrufargument übergeben)
... if __name__ == '__main__': suchstringliste=sys.argv[1:] dateiliste = "/tmp/testdatei1.txt /tmp/testdatei2.txt" egrepstring="%s" % (string.join(suchstringliste,'\|')) # baut (suchstring1|zwei|drei) zusammen ausgabe,fehler=sshcmderr(server,"""egrep \\'\(%s\)\\' %s """ % (egrepstring,dateiliste)) print ausgabe print fehler
#!/usr/bin/env python # epoch2iso iso2epoch # hella breitkopf (www.unixwitch.de) 2002-12-19 """ Usage: epoch2iso epochtime input: epoch time integer returns a date string formated YYYY-MM-DD--hhmmss a "Z" is added to mark UTC iso2epoch isotime input: "isotime" returns an epoch time integer EPOCH: Number of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer or a floating point number (to represent fractions of seconds). The Epoch is system-defined; on Unix, it is generally January 1st, 1970. (1970-01-01--000000Z (UTC)) Generate current time in epoch-format with the command: date +%s isotime: The ISO timeformat enhanced with hour, minute and seconds: YYYY-MM-DD--hhmmss Generate the current time in this format with the command: date -u +%Y-%m-%d--%H%M%S%z This program uses UTC (Universal Time Coordinated) aka. GMT (Greenwich Mean Time) aka. Zulu Time Attached timezone information other than Z or +0000 can't be used in this version, if there is no timezone information, we assume UTC, anyway. """ # Q: so, Hella, why UTC, and not the much nicer localtime? # A: It would need big effort to program around the problems of daylight-saving time # - if you use localtime without specification of timezone (with or without DST), # you have these switch-hours, where you can't make 1 to 1 assignments from localtime to epoch # I might think about a special command line option for switching this in future versions # Q: ISO 8601 recommends to put a capital "T" between date and time, why did you use "--" instead? # A: Easier to read import sys import time import os.path mytimeformatSTR="%Y-%m-%d--%H%M%S" def usage(exitvalue): print __doc__ #sys.exit(exitvalue) def epoch2iso(epochSTR): """ Usage: epoch2iso (epochtime) input: epoch time integer returns a date string formated YYYY-MM-DD--hhmmss (with attached Z for "Zulu Time") """ try: epochint=int(epochSTR) #isotime=time.strftime(mytimeformatSTR , time.localtime( epochint )) isotime=time.strftime(mytimeformatSTR , time.gmtime( epochint ))+"Z" except ValueError: print >> sys.stderr, "Error: wrong input parameter" usage(4) return(isotime) def iso2epoch(isoSTR): """ Usage: iso2epoch (isostring) isostring: date+time in the format YYYY-MM-DD--hhmmss[Z|+0000] returns epochtime """ try: #epochtime=int(time.mktime (time.strptime(isoSTR,mytimeformatSTR))) # shorten to excact 18 letters (you might have additional "Z" # (marks UTC) isoSTR,timezone=isoSTR[0:18],isoSTR[18:] # timezone might be left out, might be Z or might be "+0000" # which means we don't use anything else than UTC if (timezone !="" and timezone != "Z" and timezone != "+0000") : usage(6) #epochtime=int(time.mktime (time.strptime(isoSTR,mytimeformatSTR))) epochtime=int(time.strftime ('%s', time.strptime(isoSTR,mytimeformatSTR))) except ValueError: print >> sys.stderr, "Error: wrong input parameter" usage(4) return(4) return (epochtime) if __name__ == '__main__': # if called as single programm, do these steps: # check the input parameters # we need one parameter (more are ignored) try: inputstring=sys.argv[1] #either epochtime or isotime except IndexError: print "Error: Parameter missing" usage(4) # if help is needed help we give .. if inputstring == "--help" or inputstring == "-h" : usage(0) #with what program name were I called? programname=os.path.basename( sys.argv[0] ) #depending on program name either we convert epoch time to isotime # or isotime to epochtime ... if programname == "epoch2iso" : print epoch2iso(inputstring) elif programname == "iso2epoch" : print iso2epoch(inputstring) else: print >> sys.stderr, 'Program name was expected to be "epoch2iso" or "iso2epoch", not ',programname sys.exit(5)
import os import iso2epoch # siehe oben ... for file in os.listdir('.'): extension=file.split(basename+'.').pop() if extension.isdigit(): newname=basename +'.'+ iso2epoch.epoch2iso(extension) print newname os.rename(file,newname) os.system('gzip ' + newname) else: print file
(getestet mit Python 2.7.6)
Meine Datenbank gibt mir UTF-8:
>>> originalfromdb 'Mein sch\xc3\xb6ner Test'
Bei der Ausgabe sieht das ja eigentlich ganz gut aus …
>>> print originalfromdb Mein schöner Test >>> type(originalfromdb) >>> <type 'str'>
Wenn man diesen Strin in Python weiterverarbeiten will, bekommt man aber je nach Situation die schöne Fehlermeldung: "UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 8: ordinal not in range(128)
". Damit will Python uns sagen, dass man den String jetzt mal in richtigen Unicode umwandeln soll. Das geht so:
>>> text=unicode(originalfromdb, 'utf-8') >>> text u'Mein sch\xf6ner Test' >>> print text Mein schöner Test >>> type(text) <type 'unicode'>
Wenn ich das ganze dann zusätzlich in HTML-Entities umwandeln will (weil das dann in manchen Fällen doch noch sicherer ist als sich auf die UTF-8-Festigkeit des Empfängers zu verlassen), dann geht das so:
>>> htmltext=unicode(originalfromdb, 'utf-8').encode('ascii','xmlcharrefreplace') >>> htmltext 'Mein schöner Test'
gilt für alle Tipps, Tricks & Spickzettel:
dies sind einfache, teils banale Notizen für meinen persönlichen Gebrauch,
die hier eher zufällig auch öffentlich lesbar sind
(vielleicht hilft es ja jemandem weiter). Verwendung auf eigene Gefahr
Fehler-Hinweise, Dankesschreiben , etc. bitte an: web.21@unixwitch.de
weitere Tools / Spickzettel