Python调用含回车换行的subprocess命令时截断问题求助
问题:Python调用sed命令时因包含回车导致命令截断
我想用sed命令清理文件中的无用输出(移除ANSI控制码、回车、换行),但用Python自动化执行时,因为命令里包含回车符,导致命令被中途截断。
我的Python代码如下:
def do_stuff(): count = 0 while True: try: count += 1 basic_filename = fn + str(count) + ".txt" temp_filename = "temp_"+fn + str(count) + ".txt" final_filename = "final_"+fn + str(count) + ".txt" finalfinal_filename = "finalfinal_"+fn + str(count) + ".txt" cmd1 = b"sed -e 's/\\x1b\[[0-9;]*[mK]//g' -e 's/\r//g' -e 's/\\n//g' " + str.encode(basic_filename) + b" > " + str.encode(temp_filename) cmd1 = base64.b64encode(cmd1) cmd1 = "echo '"+bytes.decode(cmd1)+"' | base64 -d | bash" print(cmd1) except: break
示例中生成的Base64编码为:
c2VkIC1lICdzL1x4MWJcW1swLTk7XSpbbUtdLy9nJyAtZSAncy8NLy9nJyAtZSAncy9cbi8vZycgcmVzdWx0czEudHh0ID4gdGVtcF9yZXN1bHRzMS50eHQ=
解码后命令被截断,变成:
sed -e 's/\x1b\[[0-9;]*[mK]//g' -e 's/ //g' -e 's/\n//g' results1.txt > temp_results1.txt
问题原因
- 构造字节串时,
b"\r"会生成实际的回车符(ASCII 0x0D),而不是字符串形式的\r,Base64解码后命令里会出现真实的换行,bash解析时会把它当成命令换行,直接截断sed的参数。 - 用
echo传递带特殊字符的命令时,单引号无法包裹实际的换行符,bash会把换行后的内容当成新命令处理,进一步破坏原命令结构。
解决方案
方案1:直接用Python处理文件(更可靠,避免shell转义陷阱)
没必要调用sed,Python本身就能完成文件内容清理,还能彻底避开shell命令的转义坑:
import re def clean_file(input_path, output_path): # 匹配ANSI控制码的正则表达式 ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[.*?[a-zA-Z])') with open(input_path, 'r', encoding='utf-8') as f_in, open(output_path, 'w', encoding='utf-8') as f_out: content = f_in.read() # 移除ANSI控制码 content = ansi_escape.sub('', content) # 移除回车和换行符 content = content.replace('\r', '').replace('\n', '') f_out.write(content) def do_stuff(): count = 0 while True: try: count += 1 basic_filename = fn + str(count) + ".txt" temp_filename = "temp_"+fn + str(count) + ".txt" # 调用Python清理函数 clean_file(basic_filename, temp_filename) except: break
方案2:修复shell命令的转义问题
如果一定要用sed,需要确保\r和\n被转义成shell能识别的字符串(而非实际的换行/回车符),同时建议用subprocess直接执行命令,不要用Base64绕圈:
import subprocess def do_stuff(): count = 0 while True: try: count += 1 basic_filename = fn + str(count) + ".txt" temp_filename = "temp_"+fn + str(count) + ".txt" final_filename = "final_"+fn + str(count) + ".txt" finalfinal_filename = "finalfinal_"+fn + str(count) + ".txt" # 用双重转义,让shell看到的是'\r'和'\n',而非实际换行符 cmd_str = f"sed -e 's/\\x1b\\[[0-9;]*[mK]//g' -e 's/\\\\r//g' -e 's/\\\\n//g' {basic_filename} > {temp_filename}" # 直接用subprocess执行命令 subprocess.run(cmd_str, shell=True, check=True) except: break
内容的提问来源于stack exchange,提问作者David C
相关产品推荐
相关产品推荐

