python的学习笔记-打造python命令行工具(第二天)

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

2、使用sys.stdin和fileinput读取标准输入
在python标准库的sys库中,有三个文件描述符,分别是stdin,stdout,stderr,分别是标准输入、标准输出和标准出错。
a)、从标准输入读取内容(sys.stdin)
1
[root@localhost ~]# cat read.stdin.py 
2
#!/usr/bin/python
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
#!/usr/bin/python
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
#!/usr/bin/python
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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值