背景

工作需要从hive表里读取某些字段作为请求参数,调用接口返回数据并写入hive表。之前的做法是用python调用pyspark或者Scala开发spark。这次想尝试不同的方法,用python脚本的方式来实现。主要用到了subprocess模块。

知识

首先要了解python脚本操作Linux系统的一些模块和方法--subprocess模块。Python2.4版本引入了subprocess模块用来替换os.system()、os.popen()、os.spawn*()等函数以及commands模块;也就是说如果你使用的是Python 2.4及以上的版本就应该使用subprocess模块了【1】

函数

描述subprocess.run()

Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。

subprocess.call()

执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。

subprocess.check_call()

Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True)。

subprocess.check_output()

Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。

subprocess.getoutput(cmd)

接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。

subprocess.getstatusoutput(cmd)

执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。当subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()这些高级函数无法满足需求时,我们可以使用subprocess.Popen类来实现我们需要的复杂功能【1】

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

stdin,stdout,stderr参数:

默认地stdin,stdout,stderr均为None,此时表示此新进程的stdin,stdout,stderr均为默认,从keyboard获得输入,将输出和错误输出到display。如果stdin设置为PIPE,此时的stdin其实是个file对象,用来提供输入到新创建的子进程;如果stdout设置为PIPE,此时stdout其实是个file对象,用来保存新创建的子进程的输出;如果stderr设置为PIPE,此时的stderr其实是个file对象,用来保存新创建的子进程的错误输出。【2】

方法

描述Popen.poll()

用于检查子进程(命令)是否已经执行结束,没结束返回None,结束后返回状态码。

Popen.wait(timeout=None)

等待子进程结束,并返回状态码;如果在timeout指定的秒数之后进程还没有结束,将会抛出一个TimeoutExpired异常。

Popen.communicate(input=None, timeout=None)

该方法可用来与进程进行交互,比如发送数据到stdin,从stdout和stderr读取数据,直到到达文件末尾。

Popen.send_signal(signal)

发送指定的信号给这个子进程。

Popen.terminate()

停止该子进程。

Popen.kill()

杀死该子进程。

代码

import subprocess
# 读取hive表
def get_info():
sql = """
select xxx from table_name
"""
cmd = 'hive -e"""' + sql.replace('"',"\'") + ' -hiveconf mapreduce.job.queuename=xxxxx"""'
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
(out,err) = p.communicate()
if out != "":
output = bytes.decode(out)
return output.splitlines()

参考