python subprocess使用

shell中可以很方便的调用其它应用程序,将不同的应用程序组合组合起来。

python通过subprocess模块也能实现类似功能。

因为python拥有丰富的数据接口,简洁的语法,让python在进行类似的工作时比shell更容易维护。

subprocess模块是在python2.4的时候引入。详细信息查看PEP 324

介绍

subprocess主要有以下几个函数:

call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) 
check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) 
check_output(args, *, input=None, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None) 
这些函数底层都是使用Popen 类,该类拥有的方法和属性有有:
poll() 
wait(timeout=None) #timeout python3.3开始引入
communicate(input=None, timeout=None) 
send_signal(signal) 
terminate() 
kill() 
args 
stdin 
stdout
stderr 
pid 
returncode 

例子

当前例子环境为:python3.4+windows10。

主要为了实现:python调用mysql,向mysql传递命令,获取mysql执行之后的结果。

方法1:

通过变量传递和保存输入输出,使用Popen

def test1():
	child1=subprocess.Popen(['mysql','-udemo','-pdemo'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
	(stdout,stderr)=child1.communicate(input=b'use demo;\n show tables;\nexit\n')
	print(stdout.decode())
方法1还有一种写法,直接向stdin写入命令,直接从stdout读出结果:
def test11():
	child1=subprocess.Popen(['mysql','-udemo','-pdemo'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
	child1.stdin.write(b'use demo;\n show tables;\nexit\n');
	child1.stdin.close()
	print(child1.stdout.read().decode())
	child1.stdout.close()

方法2:

通过变量传递输入,将输出保存到文件中,使用Popen

def test2():
	outfile=r'result.txt'
	child1=subprocess.Popen(['mysql','-udemo','-pdemo','-s'],stdin=subprocess.PIPE,stdout=open(outfile,'wb'))
	child1.communicate(input=b'use demo;\n show tables;\nexit\n')
	if child1.returncode==0:
		with open(outfile) as f:
			print(f.read())

方法3:

通过文件传递输入,将输出保存到文件中,使用Popen

def test3():
	infile=r'sql.txt'
	outfile=r'result.txt'
	child1=subprocess.Popen(['mysql','-udemo','-pdemo','-s','-h172.16.1.141'],stdin=open(infile,'rb'),stdout=open(outfile,'wb'))
	print('input:')
	with open(infile) as f:
		print(f.read())
	print('output:')
	with open(outfile) as f:
		print(f.read())
对于方法3,还有另外一种写法,使用call:
def test31():
	infile=r'sql.txt'
	outfile=r'result.txt'
	result_code=subprocess.call(['mysql','-udemo','-pdemo','-s','-h172.16.1.141'],stdin=open(infile,'rb'),stdout=open(outfile,'wb'))
	print('input:')
	with open(infile) as f:
		print(f.read())
	if result_code==0:
		print('output:')
		with open(outfile) as f:
			print(f.read())

一些参数说明:

Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=()) 
中的stdin,stdout,stderr需要是PIPE, DEVNULL, None或者是file descriptor 。
如果传入的参数是PIPE,那么Popen会自己建立一个pipe,可以把这个pipe当做一个文件,stdin可以往里面写(写完命令之后,注意close),stdout可以从里面读。参考test11()
如果stdin是file descriptor ,需要文件中有准备好的内容,因为进程在执行的时候,会直接从这个文件中读取数据。参考test3()或test31()
Popen.communicate(input=None, timeout=None) 
 中的input需要是None,或者bytes(如果universal_newlines =True,可以是string),这个函数只能调用一次,调用之后会一直等待,直到进程停止。

总结

如果是一些简单的调用,执行使用call、check_call、check_output就行了。
如果需要更精细的控制,使用Popen可以完成。如果是进程间的通信,使用PIPE,如果仅仅传入一些命令,使用文件或者communicate中的input既可。

以上是一个例子,真正和MySQL交互的时候可以使用其提供的客户端mysql-connector直接进行交互 。


上一篇:地理数据与数据仓库


下一篇:向分析型数据库ADS中导入数据