前言
在 Python 中,subprocess 是一个非常强大的内置标准库。它的主要作用是在 Python 代码中执行外部的命令和程序(就像你在终端或命令行里敲命令一样)。
subprocess.check_output 是subprocess 模块中一个非常实用的便捷函数。它的核心作用是:执行外部命令,并直接返回该命令的标准输出(stdout)。如果命令执行失败(返回码非 0),它会自动抛出异常。
基本用法
默认情况下,check_output返回的是字节串(bytes),在python3中,我们通常会加上text=True,让它直接返回字符串。
python
import subprocess
# 执行命令,获取输出
# text=True 会将返回的 bytes 自动解码为 str
output = subprocess.check_output(["echo", "Hello World!"], text=True)
print(output)
# 输出: Hello World!
核心特性:自动检查错误(check)
函数名中的check意味着它会自动检查命令的退出状态码(returncode)。如果命令执行失败(比如命令拼错、文件不存在),它会抛出subprocess.CalledProcessError异常。
python
import subprocess
try:
# 尝试查看一个不存在的文件
output = subprocess.check_output(["ls", "not_exist.txt"], text=True)
except subprocess.CalledProcessError as e:
print(f"命令执行失败!")
print(f"返回码: {e.returncode}")
print(f"原本的命令: {e.cmd}")
处理标准错误 (stderr)
默认情况下,check_output只返回标准输出(stdout)。如果命令产生了错误信息(stderr),这些错误信息会直接打印到屏幕上,而不会被包含在返回的变量中。
如果你相把错误信息也一并合并到输出结果中,可以使用stderr=subprocess.STDOUT
python
import subprocess
# 将 stderr 合并到 stdout 中一起返回
output = subprocess.check_output(
["ls", "not_exist.txt"],
stderr=subprocess.STDOUT,
text=True
)
实战1
python
import subprocess
# 1. 定义执行单条 SQL 的函数
def run_query(cmd):
# 使用 check_output,如果 SQL 报错会自动抛出 CalledProcessError
try:
output = subprocess.check_output(cmd, universal_newlines=True)
return output.strip()
except subprocess.CalledProcessError as e:
print(f"Error executing Hive query: {e.output}")
sys.exit(1)
# 主方法
def main():
#table ='test.table_test'
#day ='2026-01-01'
# 待查询的语句
query = f"SELECT count(1) FROM {table} WHERE day = {day} "
queue_name = "root.queue.xa"
cmd = [
'spark3-sql',
'--queue', queue_name,
'-e', query]
# 执行查询
query_result = run_query(cmd)
print(query_result)
if __name__ == "__main__":
main()
实战2
python
import subprocess
import concurrent.futures
# 1. 定义执行单条 SQL 的函数
def run_query(query,queue_name='root.queue.xa'):
cmd = [
'spark3-sql',
'--queue', queue_name,
'-e', query]
# 使用 check_output,如果 SQL 报错会自动抛出 CalledProcessError
try:
output = subprocess.check_output(cmd, universal_newlines=True)
return output.strip()
except subprocess.CalledProcessError as e:
print(f"Error executing spark-sql query: {e.output}")
sys.exit(1)
# 2. 定义并发执行多条 SQL 的主函数
def run_queries_concurrent(queries_dict, max_workers=3):
results = {}
# 使用 ThreadPoolExecutor 进行并发
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交所有任务
future_to_query = {
executor.submit(run_query, sql): key
for key, sql in queries_dict.items()
}
# 获取结果 (as_completed 会在任务完成时立刻产出)
for future in concurrent.futures.as_completed(future_to_query):
key = future_to_query[future]
try:
# 设置超时时间(例如 3600 秒),防止任务永久卡死
results[key] = future.result(timeout=3600)
print(f"任务 [{key}] 执行成功!")
except Exception as e:
print(f"任务 [{key}] 发生未知错误: {e}")
return results
# 主方法
def main():
# 准备你的 SQL 字典
my_queries = {
"task_1": f"SELECT count(1) FROM test.table_test where day ='2026-06-01' ",
"task_2": f"SELECT count(1) FROM test.table_test where day ='2026-06-02' ",
"task_3": f"SELECT count(1) FROM test.table_test where day ='2026-06-03' "
}
print("开始并发执行 Spark SQL 任务...")
# 执行并发任务 (最多同时跑 3 个)
final_results = run_queries_concurrent(my_queries, max_workers=3)
print("-" * 30)
print(f"🎉 所有任务执行完毕!总耗时: {end_time - start_time:.2f} 秒")
task_1_count = int(final_results['task_1'].strip())
task_2_count = int(final_results['task_2'].strip().split('\t')[0])
task_3_count = int(final_results['task_3'].strip().split('\t')[0])
# 打印结果
print(f'task_1_count:{task_1_count}')
print(f'task_2_count:{task_2_count}')
print(f'task_3_count:{task_3_count}')
if __name__ == "__main__":
main()