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.25@unixwitch.de
weitere Tools / Spickzettel