python的学习笔记
第二天(2017-12-30)打造python命令行工具
声明:本人是每天学习赖明星《python linux系统管理与自动化运维》一书后,整理成自己的笔记,如有需要,请购买作者正版书,谢谢
1、使用sys.argv获取命令行参数
sys.argv是一个保存命令行参数的普通列表。
1
[root@localhost ~]# cat test_argv.py
2
#!/bin/python
3
from __future__ import print_function
4
import sys
5
6
print (sys.argv)
[root@localhost ~]# python test_argv.py localhost 3306
['test_argv.py', 'localhost', '3306']
1
[root@localhost ~]# cat test_argv1.py
2
#!/bin/python
3
from __future__ import print_function
4
import os
5
import sys
6
7
def main():
8
sys.argv.append("")
9
filename = sys.argv[1]
10
if not os.path.isfile(filename):
11
raise SystemExit(filename + ' does not exists')
12
elif not os.access(filename,os.R_OK):
13
raise SystemExit(filename + ' is not accessible')
14
else:
15
print(filename + ' is accessible')
16
17
if __name__ == '__main__':
18
main()
[root@localhost ~]# python test_argv1.py 2.txt
2.txt is accessible
在python标准库的sys库中,有三个文件描述符,分别是stdin,stdout,stderr,分别是标准输入、标准输出和标准出错。
a)、从标准输入读取内容(sys.stdin)
1
[root@localhost ~]# cat read.stdin.py
2
3
from __future__ import print_function
4
import sys
5
6
7
for line in sys.stdin:
8
print(line,end="")
接下来我们就可以像shell一样,通过标准输入给程序输入内容:
[root@localhost ~]# cat /etc/passwd |python read.stdin.py
[root@localhost ~]# python read.stdin.py < /etc/passwd
b)、调用文件对象读取内容(sys.stdin)
1
[root@localhost ~]# cat read.stdin.py
2
3
#coding:utf-8
4
from __future__ import print_function
5
import sys
6
7
def get_content():
8
return sys.stdin.readlines() #调用readlines函数将标准输入的内容读取到一个列表中
9
10
11
print(get_content())
12
[root@localhost ~]# cat /etc/passwd |python read.stdin.py
我们完全可以在python中用stdin代替awk进行数据处理,
fileinput可以对多文件进行处理,也可以代替awk。使用fileinput可以依次读取命令行中给出的多个文件,也就是说fileinput会遍历sys.argv[1:]列表,并按行依次读取列表中的问题,如果该文件为空,则fileinput默认读取标准输入中的内容。
在大多数情况下,我们直接调用fileinput模块中的Input方法按行读取内容即可。
例子:
1
[root@localhost ~]# cat read.stdin.py
2
3
#coding:utf-8
4
from __future__ import print_function
5
import fileinput
6
7
8
for line in fileinput.input():
9
print(line,end="")
10
11
fileinput比sys.stdin更加灵活。fileinput既可以从标准输入中读取数据,也可以从文件中读取数据,如下所示:
[root@localhost ~]# cat /etc/passwd |python read.stdin.py
[root@localhost ~]# python read.stdin.py < /etc/passwd
[root@localhost ~]# python read.stdin.py /etc/passwd
[root@localhost ~]# python read.stdin.py /etc/passwd /etc/hosts
因为fileinput可以读取多个文件内容,所以,fileinput提供了一些方法让我们知道当前读取的内容属于哪个文件,fileinput中常见的方法有:
filename:当前正在读取的文件名;fileno:文件的描述符filelineno:正在读取的行是当前文件的第几行;isfirstline:正在读取的行是否当前文件的第一行;isstdin fileinput:正在读取的文件还是直接从标准输入读取的内容。
例子:
1
[root@localhost ~]# cat test.py
2
#!/usr/bin/python
3
#coding:utf-8
4
from __future__ import print_function
5
import fileinput
6
7
for line in fileinput.input():
8
meta = [fileinput.filename(),fileinput.fileno(),fileinput.filelineno(),fileinput.isfirstline(),fileinput.isstdin()]
9
print(*meta, end=" ") #注意星号作用
10
print(line,end=" ")
11
[root@localhost ~]# python test.py /etc/passwd /etc/hosts
说明:
星号作用于函数中的形式参数,使函数具有接收可变参数的功能
星号作用于函数调用时的实际参数,单星号对应元组,双星号对应字典。对于元组,将元组中对应值传给对应参数,对于字典,将字典中对应key-value对指定的值传给对应的参数。
3、使用SystemExit异常打印错误信息
与标准输入sys.stdin类似,我们可以直接使用sys.stdout和sys.stderr向标准输出和错误输出中输出内容。
1
root@localhost ~]# cat test_stdout_stderr.py
2
#/usr/bin/python
3
#coding-utf8
4
import sys
5
6
sys.stdout.write('hello')
7
sys.stderr.write('world')
8
9
默认情况下,hello和world都会输出到命令行。我们可以通过重定向来验证hello被输出到标准输出,world被输出到了错误输出,如下:
[root@localhost ~]# python test_stdout_stderr.py
worldhello
[root@localhost ~]# python test_stdout_stderr.py > /dev/null
world
[root@localhost ~]# python test_stdout_stderr.py 2> /dev/null
hello
如果我的python程序执行失败,需要在标准错误中输出错误信息,然后以非零的返回码退出程序,那么我们就需要使用sys.stderr,如下:
1
[root@localhost ~]# cat test_stdout_stderr.py
2
#/usr/bin/python
3
#coding-utf8
4
import sys
5
6
sys.stderr.write('error message')
7
sys.exit(1)
8
[root@localhost ~]# python test_stdout_stderr.py
error message[root@localhost ~]# echo $?
1
4、使用getpass库读取密码
getpass是一个非常简单的标准库,主要包含getuser函数和getpass函数。前者用来从环境变量中获取用户名,后者用来等待用户输入密码。
1
[root@localhost ~]# cat getpass.py
2
#/usr/bin/python
3
from __future__ import print_function
4
import getpass
5
6
user = getpass.getuser()
7
passwd = getpass.getpass('please your password:')
8
print(user,passwd)
5、使用configparse解析配置文件
mysql数据库客户端默认使用/etc/my.cnf中的配置。
配置文件的好处是,配置成功后不需要每次使用时都指定相应的参数。
一个典型的配置文件包含一到多个章节(section),每个章节下可以包含一到多个选项‘(option),如MySQL的配置配置文件:
[client]
port = 3306
user = mysql
password = mysql
host = 127.0.0.1
[mysqld]
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
skip-external-locking
上面包含了client和mysqld两个章节,每个章节下有不同的选项。
1
In [3]: import ConfigParser
2
3
In [4]: cf = ConfigParser.ConfigParser(allow_no_value=True)
4
说明:allow_no_values默认为False,表示配置文件中不允许没有值。如上面的skip-external-locking这个选项就没有值。
有了ConfigParser对象以后,就可以使用read方法从配置文件中读取配置内容。
1
In [4]: cf.read('my.cnf')
2
Out[4]: ['my.cnf']
3
ConfigParser中有很多方法,其中与读取配置文件,判读文件文件相关的参数有:
1)sections:返回一个包含所有章节的列表;
2)has_section:判断章节是否存在
3)items:以元组的形式返回所有选项;
4)options:返回一个章节下所有选项的列表;
5)has_option:判断每个选项是否存在;
6)get、getboolean、getinit、getfloat:获取选项的值。get默认是返回的字符串,要返回数值使用getint,返回布尔型,使用getboolean
1
In [6]: cf.sections()
2
Out[6]: ['client', 'mysqld']
3
4
In [10]: cf.has_section('mysqld')
5
Out[10]: True
6
7
In [14]: cf.has_option('client','port')
8
Out[14]: True
9
10
11
In [18]: cf.options('client')
12
Out[18]: ['port', 'user', 'password', 'host']
13
14
15
In [20]: cf.get('client','host')
16
Out[20]: '127.0.0.1'
17
18
19
In [22]: cf.getint('client','port')
20
Out[22]: 3306
21
22
In [23]: cf.get('client','port')
23
Out[23]: '3306'
24
ConfigParser也提供了血多方法便于我们修改配置文件,如下:
1)remove_section:删除一个章节;
2)add_section:添加一个章节;
3)remove_option:删除一个选项;
4)set:添加一个选项;
5)write:将ConfigParser对象中的对象保存到文件中。
1
In [24]: cf.remove_section('client')
2
Out[24]: True
3
In [25]: cf.add_section('mysql')
4
In [26]: cf.set('mysql','host','127.0.0.1')
5
In [28]: cf.set('mysql','port','3306')
6
In [32]: cf.write(open('my_copy.cnf','w'))
7
修改完后,新的my_copy.cnf文件内容如下:
[root@localhost ~]# cat my_copy.cnf
[mysqld]
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
skip-external-locking
[mysql]
host = 127.0.0.1
port = 3306
6、使用argparse解析命令行参数
6.1 ArgumentParse解析器
使用argparse解析命令行参数时,首先需要创建一个解析器,如下:
1
In [33]: import argparse
2
In [34]: parser = argparse.ArgumentParser()
3
ArgumentParser对象的add_argument方法有如下参数:
1)name/flags:参数的名字;
2)action:遇到参数时的动作,默认值是store;
3)nargs:参数的个数,可以是具体的数字,或者是+号与*号,其中+号表示0或者多个参数,+号表示1或者多个参数;
4)const action和nargs:需要的常量值
5)default:不指定参数时的默认值
6)type:参数的类型;
7)choices:参数允许的值;
8)required:可选参数是否可以省略;
9)help:参数的帮助信息;
10)metavar:在usage说明中的参数名称;
11)dest:解析后参数名称
解析参数需要用ArgumentParser对象的parse_args方法,该方法返回一个namespace对象,获取对象后,参数值通过属性的方式进行访问。
1
[root@localhost ~]# cat test2.py
2
#/usr/bin/python
3
#cording:utf-8
4
from __future__ import print_function
5
#导入argparser库
6
import argparse
7
8
9
def __argparse():
10
#创建一个ArgumentParser解析器
11
parser = argparse.ArgumentParser(description="This is description")
12
#通过add_argument函数添加选项
13
parser.add_argument('--host',action='store',dest='server',default="localhost",help='connect to server')
14
parser.add_argument('-t',action='store_true',default=False,dest='boolean_switch',help='set a switch to true')
15
#调用parse_args函数解析命令行参数
16
return parser.parse_args()
17
18
19
def main():
20
parser = __argparse()
21
print(parser)
22
#通过parser.server获取--host选项的值
23
print('host = ',parser.server)
24
#通过parser.boolean_switch获取-t选项的值
25
print('boolean_switch=',parser.boolean_switch)
26
27
if __name__ == '__main__':
28
main()
29
在上面的例子中,我们首先导入argparser库,然后在__argparse函数中创建一个ArgumentParser解析器,并通过add_argument函数添加选项。选项添加完后,调用parse_args函数解析命令行参数。在main函数中,我们可以通过parser.server获取--host选项的值,通过parser.boolean_switch获取-t选项的值。
1
[root@localhost ~]# python test2.py
2
Namespace(boolean_switch=False, server='localhost')
3
host = localhost
4
boolean_switch= False
5
6
7
[root@localhost ~]# python test2.py --host=127.0.0.1 -t
8
Namespace(boolean_switch=True, server='127.0.0.1')
9
host = 127.0.0.1
10
boolean_switch= True
11
使用argparser进行参数解析还有一个好处是,它能根据我们的选项定义自动生成帮助信息,例如:
1
[root@localhost ~]# python test2.py --help
2
usage: test2.py [-h] [--host SERVER] [-t]
3
4
This is description
5
6
optional arguments:
7
-h, --help show this help message and exit
8
--host SERVER connect to server
9
-t set a switch to true
10
6.2 模仿MySQL客户端的命令行参数
1
[root@localhost ~]# cat mysql.py
2
#/usr/bin/python
3
#coding:utf-8
4
from __future__ import print_function
5
import argparse
6
7
8
def __argparse():
9
parser = argparse.ArgumentParser(description='A python-mysql client')
10
parser.add_argument('--host',action='store',dest='host',required=True,help='connect to host')
11
parser.add_argument('-u','--user',action='store',dest='user',required=True,help='user for login')
12
parser.add_argument('-p','--password',action='store',dest='password',required=True,help='password to use where connect to server')
13
parser.add_argument('-P','--port',action='store',dest='port',default=3306,type=int,help='port number to use for connection or 3306 for default')
14
parser.add_argument('-v','--version',action='version',version='%(prog)s 0.1')
15
return parser.parse_args()
16
17
18
def main():
19
parser = __argparse()
20
conn_args = dict(host=parser.host,user=parser.user,password=parser.password,port=parser.port)
21
print(conn_args)
22
23
if __name__ == '__main__':
24
main()
25
1
[root@localhost ~]# python mysql.py --help
2
usage: mysql.py [-h] --host HOST -u USER -p PASSWORD [-P PORT] [-v]
3
4
A python-mysql client
5
6
optional arguments:
7
-h, --help show this help message and exit
8
--host HOST connect to host
9
-u USER, --user USER user for login
10
-p PASSWORD, --password PASSWORD
11
password to use where connect to server
12
-P PORT, --port PORT port number to use for connection or 3306 for default
13
-v, --version show program's version number and exit
14
1
[root@localhost ~]# python mysql.py --host=127.0.0.1 -u=root -p=123
2
{'host': '127.0.0.1', 'password': '123', 'port': 3306, 'user': 'root'}
3
7、使用logging记录日志
7.1、python的logging模块
注意:1.命名py脚本时,不要与python预留字,模块名等相同,否则运行的脚本会报错
1
[root@localhost ~]# cat test_logging.py
2
#!/usr/local/bin/python
3
#coding:utf-8
4
import logging
5
6
7
logging.debug('debug message')
8
logging.info('info message')
9
logging.warn('warn message')
10
logging.error('error message')
11
logging.critical('critical message')
12
程序的执行结果如下:
[root@localhost ~]# python test_logging.py
WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message
7.2、配置日志格式
在使用logging记录日期之前,我们需要进行一些简单的设置,如下:
1
[root@localhost ~]# cat test_logging.py
2
#!/usr/local/bin/python
3
#coding:utf-8
4
import logging
5
6
logging.basicConfig(filename='app.log',level=logging.INFO)
7
8
logging.debug('debug message')
9
logging.info('info message')
10
logging.warn('warn message')
11
logging.error('error message')
12
logging.critical('critical message')
13
[root@localhost ~]# python test_logging.py
[root@localhost ~]# cat app.log
INFO:root:info message
WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message
我们先了解logging模块中的几个概念,即Logger、Handler及Formatter。
Logger:日志记录器,是应用程序中能直接使用的接口;
Handler:日志处理器,用以表明将日志保存到什么地方以及保存多久;
Formatter:格式化,用以格式化日志的输出格式。
在典型的使用场景中,一个日志记录器使用一个日志处理器,一个日志处理器使用一个日志格式化。
对于比较简单的脚本,可以直接使用basicConfig在代码中配置日志;对于比较复杂的项目,可以将日志保存到一个配置文件中,然后在代码中使用fileConfig函数读取配置文件。
例子:
1
[root@localhost ~]# vim test_logging.py
2
3
#!/usr/local/bin/python
4
#coding:utf-8
5
import logging
6
7
logging.basicConfig(filename='app.log',level=logging.debug,format='%(asctime)s:%(levelname)s:%(message)s')
8
9
logging.debug('debug message')
10
logging.info('info message')
11
logging.warn('warn message')
12
logging.error('error message')
13
logging.critical('critical message')
14
对于复杂的项目,一般将日志配置保存到配置文件中,例如下面是一个典型的配置文件:
1
[root@localhost ~]# cat logging.cnf
2
[loggers]
3
keys = root
4
5
[handlers]
6
keys = logfile
7
8
[formatters]
9
keys = generic
10
11
#定义root这个logger所使用的handler
12
[logger_root]
13
handlers = logfile
14
15
#定义handler输出日志的方式、日志文件的切换时间等
16
[handler_logfile]
17
class = handlers.TimedRotatingFileHandler
18
args = ('app.log','midnight',1,10)
19
level = DEBUG
20
formatter = generic
21
22
#定义日志的格式,包括日志产生的时间、日志的级别、产生日志的文件名和行号等信息
23
[formatter_generic]
24
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s] %(message)s
25
有了配置文件后,在python代码中使用logging.config模块的fileConfig函数加载日志配置,如下所示:
1
[root@localhost ~]# cat test_logging.py
2
#!/usr/local/bin/python
3
#coding:utf-8
4
import logging
5
import logging.config
6
7
logging.config.fileConfig('logging.cnf')
8
9
logging.debug('debug message')
10
logging.info('info message')
11
logging.warn('warn message')
12
logging.error('error message')
13
logging.critical('critical message')
14
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28916011/viewspace-2149515/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28916011/viewspace-2149515/