Pythonconfigparser模块与subprocess模块

configparser 模块

Python中 configparser 模块用于读取和编辑配置文件,更多的是用于读取配置文件。配置文件的格式如下,可以包含多个section(例如:db,email),每个section又可以有多个键值对(例如:database=bps);其中 '=' 也可以使用 ':' 取代~

10年积累的网站设计、成都做网站经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先做网站设计后付款的网站建设流程,更有阳新免费网站建设让你可以放心的选择与我们合作。

[default]
log_path=/tmp/csv.log

[db]
host=192.168.1.20
database=bps
user=bps
password=123456

[email]
smtp_server=1.2.3.4
smtp_port=587
mailfrom=kitty@163.com
mailfrom_pass=123456

生成配置文件

生成如上示例的配置文件:

import configparser

config = configparser.ConfigParser()
config['default'] = {'log_path': '/tmp/csv.log'}

config['db'] = {'host': '192.168.1.20',
                'database': 'bps',
                'user': 'bps',
                'password': '123456'}

config['email'] = {'smtp_server': '1.2.3.4',
                'smtp_port': '587',
                'usmailfromer': 'kitty@163.com',
                'mailfrom_pass': '123456'}

# 写入到配置文件,执行 config.ini 配置文件的路径为当前路径~
with open(file='config.ini',mode='w') as f:
    config.write(f)

执行后,在当前目录下,可以看到已生成的 config.ini 文件:
Python configparser模块 与 subprocess 模块

文件内容如下:
Python configparser模块 与 subprocess 模块

读取配置文件

更多的时候,我们是手动编辑配置文件,在程序运行时读取配置信息。

config = configparser.ConfigParser()
print(config.sections())   # []

# 读取配置文件 config.ini
config.read('config.ini')

# 打印 config.ini 文件中的所有 section,以列表的形式返回
print(config.sections())    # ['default', 'db', 'email']

# 判断指定的 section 是否存在
print('email' in config)       # True
print('log_path' in config)  # False
# 或
print(config.has_section('email'))        # True
print(config.has_section('log_path'))   # False

# 打印 config.ini 文件中 指定 section 下的所有 option,以列表的形式返回
print(config.options('email'))   # ['smtp_server', 'smtp_port', 'usmailfromer', 'mailfrom_pass']

# 判断 指引的 option 是否存在
print('log_path' in config['default'])         # True
# 或
print(config.has_option('email', 'abc'))  # False

# 打印 config.ini 文件中 指定 section 下的所有 键值对
print(config.items('db'))      # [('host', '192.168.1.20'), ('database', 'bps'), ('user', 'bps'), ('password', '123456')]

# 获取 config.ini 文件中 指定 section 下的指定 option 的值,以字符串的形式返回
print(config.get('email', 'smtp_server'))    # 1.2.3.4
# 或
print(config['email']['smtp_server'])         # 1.2.3.4

 

遍历指定 section 下的所有key

for key in config['db']:
    print(key)

结果输出:
host
database
user
password

编辑配置文件

除了读写操作,还可以对已有的配置文件进行编辑。

config = configparser.ConfigParser()

# 读取配置文件
config.read('config.ini')

# 增加一个section
if not config.has_section('sftp'):
    config.add_section('sftp')

# 删除一个section
config.remove_section('email')

# 添加一个 option
if not config.has_option('sftp', 'sftp_server'):
    config.set('sftp', 'sftp_server', '4.3.2.1')

# 删除一个 option
config.remove_option('db', 'database')

# 修改一个 option
if config.has_option('db', 'user'):
    config.set('db', 'user', 'baby')

注意:以上这些操作只发生在内存中,若要使文件改变,还需要写入到文件中

with open(file='config.ini', mode='w') as f:
    config.write(f)

再次查看文件,文件内容已经发生修改:
Python configparser模块 与 subprocess 模块

subprocess 模块

subprocess 模块用于执行外部命令。在python中,可以使用标准库中的 subprocess模块 来fork一个子进程,然后使用子进程执行外部命令。主程序可以通过 subprocess模块 提供的一些管理标准流(standard stream) 和 管道(pipe) 的工具来获取外部命令的执行结果,以及子进程的执行状态码~

os.system() 和 os.popen()

os.system() 会打开一个子shell(子进程)来执行系统命令,命令的执行结果会输出到stdout,也就是直接打印到终端,方法会返回状态码,如下所示:

import os

return_code = os.system('ls -l /tmp')
print(return_code)

# 输出结果:
lrwxr-xr-x@ 1 root  wheel  11 Sep 25 20:16 /tmp -> private/tmp
0

 
os.popen() 的执行会将外部命令的执行结果输出到管道,方法返回一个连接管道的文件对象。如果外部命令执行成功,则不会返回状态码,若执行失败,错误信息会输出到stdout(即直接打印到终端),并返回一个空字符串。操作该文件对象的方式与普通的读写文件操作一致,如下示例:

import os

f = os.popen('cat /Users/James/abc')
print(f.readlines())

# 输出结果:
['hello\n', 'kitty\n']

 
和 subprocess模块 一样,以上两种方式也可以用来执行外部命令,但是这两个方法过于简单,不能完成复杂的操作,例如管理命令的输入输出,获取命令的运行状态等~,subprocess 模块可以满足这些需求,所以如官方建议,使用subprocess模块来生成新进程并获取结果是更好的选择。
 
在 subprocess 模块中,有很多个函数,这些函数都有各自的方式创建子进程,执行外部命令~

subprocess.run()

run方法 会直接输出命令的执行结果,并返回 CompletedProcess 对象

code = subprocess.run(["df","-h"])   # 输出命令的执行结果
print(code)              # CompletedProcess(args=['df', '-h'], returncode=0)

# 获取命令的状态码
print(code.returncode)   # 0
subprocess.call()

call方法 会直接输出命令的执行结果,并返回 状态码

res = subprocess.call(["ls","-l"])   # 输出命令的执行结果

# 获取命令的状态码
print(res)    # 0
subprocess.check_call()

check_call 方法内部其实调用了call方法,当状态码为0时,同call方法一致,若状态码不为0,则抛出 CalledProcessError 异常

res = subprocess.check_call(["ls","-l"])
print(res)    # 0
subprocess.check_output()

check_output方法 接收的参数只能是一个没有参数的外部命令,返回执行的结果,内部实现方式是调用了 run 方法

res = subprocess.check_output("pwd")
print(res)     # 即返回当前路径
subprocess.getstatusoutput()

getstatusoutput方法 接受字符串形式的命令,返回 一个元组形式的结果,第一个元素是命令执行状态,第二个为执行结果

res = subprocess.getstatusoutput('ls -l /tmp')
print(res)      # (0, 'lrwxr-xr-x@ 1 root  wheel  11 Sep 25 20:16 /tmp -> private/tmp')

 

若执行错误,则同样会返回错误信息

res = subprocess.getstatusoutput('abc')
print(res)

# 结果输出:
(127, '/bin/sh: abc: command not found')
subprocess.getoutput()

getoutput方法 接受字符串形式的命令,返回执行结果,不会返回状态码

res = subprocess.getoutput('ls -l /tmp/')
print(res)

# 结果输出:
total 8
......
......
-rw-r--r--  1 baby  wheel  446 Dec 21 14:14 csv.log
drwxr-xr-x  2 root  wheel   64 Dec 19 15:03 powerlog

以上这些方法都是直接或者间接的调用了subprocess.Popen 方法,建议在使用过程中直接使用 subprocess.Popen 方法~

subprocess.Popen()

res = subprocess.Popen("cat /etc/passwd", shell=True)   

# 结果输出(即 /etc/passwd 文件的内容):
##
# User Database
...
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
......
......

subprocess.Popen 方法创建的子进程执行外部命令后,会将返回结果 输出到 stdin/stdout/stderr 中,这样会直接打印到终端。也可以将返回信息写入到一个缓存区(或称之为管道),主进程从缓存区中读取子进程的返回信息~

res = subprocess.Popen("cat /tmp/csv.log", shell=True, stdout=subprocess.PIPE)
print(res.stdout.read())

# 结果输出:
b'abc\n'

 
将正确输出和错误输出都写入到缓存区中

res = subprocess.Popen("lm /tmp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(res.stdout.read())   # b''
print(res.stderr.read())     # b'/bin/sh: lm: command not found\n'

 
也可以利用 subprocess.PIPE 将多个子进程的输入和输出连接在一起,构成管道(pipe),即 s1 的输出结果作为 s2 的输入信息:

s1 = subprocess.Popen(["cat", "/etc/passwd"], stdout=subprocess.PIPE)
s2 = subprocess.Popen(["grep", "0:0"], stdin=s1.stdout, stdout=subprocess.PIPE)
out = s2.communicate()
print(out)

# 输出结果:
(b'root:*:0:0:System Administrator:/var/root:/bin/sh\n', None)

 
其中的 communicate() 方法下面会介绍~

注意::运行 subprocess.Popen() 后,主进程不会等待子进程执行完毕,而是会继续往下执行~

poll()

poll 方法用于判断子进程是否执行完毕,若没有执行完毕返回 None,若是执行完成,返回 执行状态码~

res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(res.poll())    # None
time.sleep(6)
print(res.poll())    # 0
wait()

wait方法 会等待命令执行完成(即主进程阻塞),并且返回 执行状态码~

res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# 等待子进程执行完毕,并返回状态码
print(res.wait())      # 0
terminate()

terminate方法能终止正在运行中的子进程

res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
res.terminate()

# 子进程被终止后,没有返回信息
print(res.stdout.read())    # b''
获取子进程的pid

pid 为 subprocess.Popen 对象的一个变量,保存了子进程的进程号

res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(res.pid)       # 36777
communicate()

执行 communicate 方法后,主进程会等待(主进程阻塞)子进程运行完毕,并从 subprocess.PIPE 中会获取子进程的返回信息,返回一个tuple(标准输出和错误输出)

res = subprocess.Popen("sleep 5;echo 'end'", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(res.communicate())     # 主进程执行到这一步,不再继续往下执行,会等待子进程运行完毕~

# 错误输出
res = subprocess.Popen("lm -l", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(res.communicate())

# 结果输出:
(b'end\n', b'')
(b'', b'/bin/sh: lm: command not found\n')

.................^_^


文章名称:Pythonconfigparser模块与subprocess模块
文章来源:http://ybzwz.com/article/jgcjpj.html