Python3 Subprocess在Windows下执行type合并文件无预期输出
问题原因
- subprocess参数与shell重定向逻辑冲突
你在调用Popen时指定了stdout=subprocess.PIPE,该参数会强制把子进程的标准输出捕获到Python进程的管道中,优先级高于shell层面> file3的重定向规则,导致合并后的内容没有写入目标文件。你看到的165字节文件,大概率是type命令执行时输出的错误提示(比如找不到文件、编码警告等)。 - 命令传参格式错误
如果传递给Popen的COMMAND参数是列表格式(比如['type', 'file1', 'file2', '>', 'file3']),开启shell=True时,>和后续的文件名不会被shell解析为重定向逻辑,而是会被当成type命令的输入文件参数,type找不到对应文件就会输出错误信息,写入到目标文件中,导致文件大小异常。 - 内置命令解析差异
type是cmd.exe的内置命令,不是独立可执行程序,当shell=True时,cmd对命令字符串的解析规则和手动执行cmd存在差异,如果文件名包含空格、特殊字符未正确转义,会导致type实际只读取到部分参数,输出内容不完整。 - 二进制文件处理问题
如果合并的是二进制文件,cmd下的type命令默认会按文本编码解析文件内容,遇到EOF标记会提前终止读取,也会导致输出文件大小异常。
解决方案
方案1:修改subprocess调用参数适配shell规则
如果你希望继续使用系统命令+shell重定向的实现方式,按如下规则调整:
- 去掉
stdout=subprocess.PIPE参数,让shell的重定向逻辑正常生效 - 传入的
COMMAND必须是完整的字符串格式,不要用列表格式 - 文件名包含空格时需要给文件名加双引号转义
修改后的函数示例:
import subprocess def RUN_SUBPROCESS(COMMAND, LOG): print('#### STARTING SUB PROCESS') # 仅捕获错误输出,标准输出交给shell重定向处理 SUB_PROCESS = subprocess.Popen(COMMAND, shell=True, stderr=subprocess.PIPE) out, err = SUB_PROCESS.communicate() SUB_PROCESS.wait() if LOG == 'true': print('#### OUTPUT') print(out) print('#### ERROR') print(err) print('#### SUB PROCESS COMPLETE') return # 调用示例,文件名含空格时加双引号 RUN_SUBPROCESS('type "文件1.txt" "文件2.txt" > 合并后文件.txt', LOG='true')
方案2:纯Python实现文件合并(推荐)
不需要调用系统命令,直接用Python读写文件实现合并,完全规避跨平台兼容问题,文本、二进制文件都适用:
def merge_files(input_file_list, output_file_path): # 二进制读写避免编码问题 with open(output_file_path, 'wb') as out_file: for input_file in input_file_list: with open(input_file, 'rb') as in_file: out_file.write(in_file.read()) # 调用示例 merge_files(['file1', 'file2'], 'file3')
该方案不需要考虑系统差异,Windows、Linux都可以正常运行,也不需要处理命令转义、shell调用的各类异常,稳定性更高。
方案3:保留stdout捕获逻辑,直接写入文件
如果确实需要捕获命令输出,就去掉shell层面的重定向,直接把communicate()返回的输出内容写入目标文件:
def RUN_SUBPROCESS(COMMAND, output_file=None, LOG='false'): print('#### STARTING SUB PROCESS') SUB_PROCESS = subprocess.Popen(COMMAND, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = SUB_PROCESS.communicate() SUB_PROCESS.wait() if output_file: with open(output_file, 'wb') as f: f.write(out) if LOG == 'true': print('#### OUTPUT') print(out) print('#### ERROR') print(err) print('#### SUB PROCESS COMPLETE') return # 调用示例 RUN_SUBPROCESS('type file1 file2', output_file='file3', LOG='true')
内容的提问来源于stack exchange,提问作者user72261
相关产品推荐
相关产品推荐

