python中那纠结的os.system()与空格处理

原贴地址:http://www.cnblogs.com/ini_always/archive/2011/09/26/2192205.html


今天在写一个用来对vmware workstation虚拟机进行操作的小脚本,主要原理是用python来调用vmrun.exe,传递各种不同的参数给它,来进行不同的操作。

原理很简单,实现。。。其实也很简单,你会说:不就是一个os.system()调用吗?是的,我也是这么想的。

我把vmware装在program files目录下,其完整路径为:C:\Program Files\VMware\VMware Workstation\vmrun.exe,你肯定注意到了,路径中有空格,于是,你会说,那加个双引号括起来不就行了嘛。是的,我也是这么想的。

但是关键是,我们都这么想,程序不这么想,运行时,程序报出'C:\Program' is not recognized as an internal or external command, operable program or batch file.的错误,这一看就是典型的路径中存在空格的错误,你会怀疑说,你加引号没?我的第一反应也是怀疑加引号没?但这个确实加了。

不管你糊涂没有,反正我到这一步是糊涂了,既然引号加了,但从结果来看,os.system()还是用空格把字符串给拆成了不同的部分,然后再调用shell来执行。但我后来在实验的过程中又发现了一个奇怪的问题:如果参数只是一个加引号的字符串,os.system()就可以正常执行,但如果有多个引号对,就会出现以上错误。也就是说,如果参数类似"xx yy zz"这样的类型,os.system()可以成功执行;如果参数类似"xx yy" "aa bb"这样的类型,os.system()就会出错。

这一下子引起了我的好奇心,想去看看os.system()的源代码是怎么处理的,但死活没有找到,唉,又要被这该死的好奇心折磨了。

最后说一下解决方法,就是用subprocess.Popen()代替os.system(),如下:

ps = subprocess.Popen(cmd);
ps.wait(); #让程序阻塞

最最后,附上python中对os.system()函数的说明:

复制代码
Execute the command (a string) in a subshell. This is implemented by calling the Standard C function system(),
and has the same limitations
. Changes to posix.environ, sys.stdin, etc. are not reflected in the environment
of the executed command.

On Unix, the return value is the exit status of the process encoded in the format specified for wait(). Note
that POSIX does not specify the meaning of the return value of the C system() function, so the return value
of the Python function is system-dependent.


On Windows, the return value is that returned by the system shell after running command, given by the Windows
environment variable COMSPEC: on command.com systems (Windows 95, 98 and ME) this is always 0; on cmd.exe
systems (Windows NT, 2000 and XP) this is the exit status of the command run; on systems using a non-native
shell, consult your shell documentation.


Availability: Macintosh, Unix, Windows.

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results;
using that module is preferable to using this function.
复制代码

可以看出,os.system()是调用了C语言的标准函数system(),不过那个那个红红的limitations单词说明这个方法有其局限性。最后一句话话说,subprocess模块更加强大,并建议我们尽量使用subprocess模块。

所以,应该尽量不要使用os.system()方法,而是用subprocess中的Popen对象或者call()方法代替,以免产生不可预知的错误。

==================================我是刚猛的分界线==================================

写完文章,才发现python的官方网站上有人提交这个bug:http://bugs.python.org/issue1524,不过这个bug在07年就提交了,但看结果是wont fix(不会修复),看后面的评论,原来是os.system()只是简单地把字符串传递给system()函数,自己并不会对字符串进行处理,所以这个bug应该是system()函数的问题或者windows shell的问题,这确实不是python能修复的。  ^_^

bug: 眼图生成失败: name 'plot_eye_diagrams' is not defined。请不要纠结了。请不要再继续错上加错,我这里这份代码确认可用。在这上面加注释就行。要求: 1、包含超级详细的代码注释 2、包含尽可能多的运用到的编程知识的介绍 3、每一处正则表达式都要进行不遗余力的讲解 # ===================================================== # 导入必要的库模块 # ===================================================== import numpy as np # 科学计算库 import matplotlib.pyplot as plt # 数据可视化库 import re # 正则表达式模块 import datetime # 日期时间处理 from matplotlib.lines import Line2D # 图例元素 import os # 操作系统接口 from collections import defaultdict # 带默认值的字典 # ===================================================== # 健壮的文件读取函数 # ===================================================== def robust_read_file(file_path): """ 健壮的文件读取函数,处理不同编码的文件 参数: file_path - 文件在电脑上的完整路径 """ try: with open(file_path, 'r', encoding='utf-8') as f: return f.read() except UnicodeDecodeError: try: with open(file_path, 'r', encoding='latin-1') as f: content = f.read() return re.sub(r'[\x00-\x1F]+', '', content) # 删除控制字符 except Exception as e: print(f"文件解码错误: {e}") return None # ===================================================== # 日志解析函数(修改:只对读方向应用偏移) # ===================================================== def parse_log_file(log_content, normalization_point): """ 解析DDR校准日志文件,提取关键数据 参数: log_content - 日志文件的内容 normalization_point - 归一化点(十六进制值) """ # 创建空字典存储解析结果 data = {} # {vref: {dq_index: {direction: (min, max, window)}}} # 初始化当前处理的变量 current_vref = None # 当前处理的vref值 pending_data = {} # 临时存储待处理的数据 current_offset = None # 当前偏移量 raw_data = {} # 存储原始数据(偏移前)用于输出 # 按行处理日志内容 for line in log_content.split('\n'): line = line.strip() if not line: continue # 匹配vref行(十六进制值) vref_match = re.match(r'.*vref:\s*0x([0-9a-fA-F]+)', line) if vref_match: hex_str = vref_match.group(1) current_vref = int(hex_str, 16) data[current_vref] = {} raw_data[current_vref] = {} pending_data = {} current_offset = None continue # 匹配0x38c行(简写形式) offset_match = re.match(r'.*0x38c:\s*(?:0x)?([0-9a-fA-F]+)', line) if offset_match and current_vref is not None: try: hex_str = offset_match.group(1) offset_value = int(hex_str, 16) current_offset = normalization_point - offset_value except ValueError: print(f"警告: 无法解析偏移量: {offset_match.group(1)}") current_offset = None continue # 匹配max点(十进制值) max_match = re.match(r'.*dq(\d+)\s+max_(\w+)_point\s*:\s*(-?\d+)', line) if max_match and current_vref is not None: dq_index = int(max_match.group(1)) direction = max_match.group(2) max_val = int(max_match.group(3)) key = (dq_index, direction) # 存储原始值(不应用偏移) if current_vref not in raw_data: raw_data[current_vref] = {} if dq_index not in raw_data[current_vref]: raw_data[current_vref][dq_index] = {} if direction not in raw_data[current_vref][dq_index]: raw_data[current_vref][dq_index][direction] = {'min': None, 'max': None} raw_data[current_vref][dq_index][direction]['max'] = max_val # 只有读方向应用偏移 if direction == 'read' and current_offset is not None: max_val += current_offset pending_data[key] = {'max': max_val} continue # 匹配min点(十进制值) min_match = re.match(r'.*dq(\d+)\s+min_(\w+)_point\s*:\s*(-?\d+)', line) if min_match and current_vref is not None: dq_index = int(min_match.group(1)) direction = min_match.group(2) min_val = int(min_match.group(3)) key = (dq_index, direction) # 存储原始值(不应用偏移) if current_vref not in raw_data: raw_data[current_vref] = {} if dq_index not in raw_data[current_vref]: raw_data[current_vref][dq_index] = {} if direction not in raw_data[current_vref][dq_index]: raw_data[current_vref][dq_index][direction] = {'min': None, 'max': None} raw_data[current_vref][dq_index][direction]['min'] = min_val # 只有读方向应用偏移 if direction == 'read' and current_offset is not None: min_val += current_offset if key in pending_data: pending_data[key]['min'] = min_val continue # 匹配窗口行(十进制值) win_match = re.match(r'.*dq(\d+)\s+(\w+)_windows\s*:\s*(-?\d+)', line) if win_match and current_vref is not None: dq_index = int(win_match.group(1)) direction = win_match.group(2) windows = int(win_match.group(3)) key = (dq_index, direction) if key in pending_data and 'min' in pending_data[key] and 'max' in pending_data[key]: min_val = pending_data[key]['min'] max_val = pending_data[key]['max'] max_delay = 0x7F if direction == 'read' else 0xFF min_val = max(0, min_val) max_val = min(max_delay, max_val) if min_val > max_val or windows < 0: result = None else: window_size = max_val - min_val + 1 result = (min_val, max_val, window_size) if dq_index not in data[current_vref]: data[current_vref][dq_index] = {} data[current_vref][dq_index][direction] = result del pending_data[key] # 返回解析结果和原始数据 return data, raw_data # ===================================================== # 眼图指标计算函数 # ===================================================== def calculate_eye_metrics(data, avddq, dq_index, direction): """ 计算眼图的最大宽度和最大高度 参数: data - 解析后的日志数据 avddq - AVDDQ电压值 dq_index - DQ索引(0-15) direction - 方向('read'或'write') """ max_eye_height = 0.0 max_eye_width = 0.0 voltage_windows = defaultdict(float) for vref, dq_data in data.items(): voltage = (vref / 0x1FF) * avddq dq_info = dq_data.get(dq_index, {}).get(direction) if dq_info is None: continue min_point, max_point, window_size = dq_info window_size = max_point - min_point + 1 max_delay = 0x7F if direction == 'read' else 0xFF ui_range = 2 if direction == 'read' else 4 window_ui = (window_size / max_delay) * ui_range if window_ui > max_eye_width: max_eye_width = window_ui voltage_windows[voltage] = window_ui sorted_voltages = sorted(voltage_windows.keys()) current_height = 0 max_height = 0 for i in range(1, len(sorted_voltages)): voltage_diff = sorted_voltages[i] - sorted_voltages[i-1] if sorted_voltages[i] in voltage_windows and sorted_voltages[i-1] in voltage_windows: current_height += voltage_diff if current_height > max_height: max_height = current_height else: current_height = 0 max_eye_height = max_height return max_eye_width, max_eye_height # ===================================================== # 眼图数据生成函数 # ===================================================== def generate_eye_diagram(data, avddq, ui_ps, dq_index, direction): """ 生成眼图数据点 参数: data - 解析后的日志数据 avddq - AVDDQ电压值 ui_ps - 每个UI的时间(皮秒) dq_index - DQ索引(0-15) direction - 方向('read'或'write') """ pass_points = [] fail_points = [] max_delay = 0x7F if direction == 'read' else 0xFF ui_range = 2 if direction == 'read' else 4 for vref, dq_data in data.items(): voltage = (vref / 0x1FF) * avddq dq_info = dq_data.get(dq_index, {}).get(direction) for delay in range(0, max_delay + 1): ui_value = (delay / max_delay) * ui_range if dq_info is None: fail_points.append((ui_value, voltage)) else: min_point, max_point, _ = dq_info if min_point <= delay <= max_point: pass_points.append((ui_value, voltage)) else: fail_points.append((ui_value, voltage)) return pass_points, fail_points # ===================================================== # 输出原始数据到新日志(新增函数) # ===================================================== def export_raw_data(raw_data, normalization_point, log_path): """ 输出原始数据到新日志文件(按DQ划分) 参数: raw_data - 原始数据(偏移前) normalization_point - 归一化点 log_path - 原始日志文件路径 """ # 获取当前时间戳 timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") # 获取日志文件名(不含扩展名) log_filename = os.path.basename(log_path) if '.' in log_filename: log_name = log_filename.rsplit('.', 1)[0] else: log_name = log_filename # 创建输出目录 log_dir = os.path.dirname(log_path) or os.getcwd() output_dir = os.path.join(log_dir, "raw_data_export") os.makedirs(output_dir, exist_ok=True) # 创建输出文件路径 output_file = os.path.join(output_dir, f"{log_name}_raw_data_{timestamp}.txt") # 写入原始数据 with open(output_file, 'w', encoding='utf-8') as f: # 写入标题信息 f.write("=" * 80 + "\n") f.write(f"DDR校准原始数据报告 (归一化点: 0x{normalization_point:X})\n") f.write(f"生成时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"原始日志: {log_path}\n") f.write("=" * 80 + "\n\n") # 按vref排序 sorted_vrefs = sorted(raw_data.keys()) for vref in sorted_vrefs: # 写入vref标题 f.write(f"VREF: 0x{vref:03X}\n") f.write("-" * 60 + "\n") # 按DQ索引排序 sorted_dq = sorted(raw_data[vref].keys()) for dq_index in sorted_dq: # 写入DQ标题 f.write(f" DQ{dq_index}:\n") # 处理读方向数据 if 'read' in raw_data[vref][dq_index]: rd = raw_data[vref][dq_index]['read'] f.write(f" 读方向:\n") f.write(f" 原始最小值: {rd['min']}\n") f.write(f" 原始最大值: {rd['max']}\n") f.write(f" 窗口大小: {rd['max'] - rd['min'] + 1}\n") # 处理写方向数据 if 'write' in raw_data[vref][dq_index]: wr = raw_data[vref][dq_index]['write'] f.write(f" 写方向:\n") f.write(f" 原始最小值: {wr['min']}\n") f.write(f" 原始最大值: {wr['max']}\n") f.write(f" 窗口大小: {wr['max'] - wr['min'] + 1}\n") f.write("\n") f.write("\n") print(f"原始数据已导出至: {output_file}") return output_file # ===================================================== # 眼图绘制函数 # ===================================================== def plot_eye_diagrams(log_content, data_rate, avddq, log_path, normalization_point): """ 绘制DDR眼图 参数: log_content - 日志内容 data_rate - 数据速率(Mbps) avddq - AVDDQ电压(V) log_path - 日志文件路径 normalization_point - 归一化点 """ # 计算UI时间(皮秒) ui_ps = (1 / (data_rate * 1e6)) * 1e12 # 解析日志文件(获取处理后的数据和原始数据) data, raw_data = parse_log_file(log_content, normalization_point) # 导出原始数据到新日志 raw_data_file = export_raw_data(raw_data, normalization_point, log_path) # 检查是否解析到有效数据 if not data: print("错误: 无法从日志中解析出有效数据") return None, None # 创建图表对象 fig_write, axes_write = plt.subplots(4, 4, figsize=(20, 20)) fig_read, axes_read = plt.subplots(4, 4, figsize=(20, 20)) # 设置标题(包含原始数据文件路径) norm_title = f" (归一化点: 0x{normalization_point:X}, 原始数据: {os.path.basename(raw_data_file)})" fig_write.suptitle(f'DDR写眼图 (数据速率: {data_rate} Mbps, UI: {ui_ps:.2f} ps){norm_title}', fontsize=18) fig_read.suptitle(f'DDR读眼图 (数据速率: {data_rate} Mbps, UI: {ui_ps:.2f} ps){norm_title}', fontsize=18) # 展平坐标轴数组 axes_write = axes_write.flatten() axes_read = axes_read.flatten() # 创建图例元素 legend_elements = [ Line2D([0], [0], marker='o', color='w', label='通过', markerfacecolor='green', markersize=10), Line2D([0], [0], marker='o', color='w', label='失败', markerfacecolor='red', markersize=10) ] # 遍历16个DQ通道 for dq_index in range(16): # 计算写眼图指标 write_width, write_height = calculate_eye_metrics(data, avddq, dq_index, 'write') # 生成写眼图数据点 write_pass, write_fail = generate_eye_diagram(data, avddq, ui_ps, dq_index, 'write') # 计算读眼图指标 read_width, read_height = calculate_eye_metrics(data, avddq, dq_index, 'read') # 生成读眼图数据点 read_pass, read_fail = generate_eye_diagram(data, avddq, ui_ps, dq_index, 'read') # 绘制写眼图 if write_fail: x_fail, y_fail = zip(*write_fail) axes_write[dq_index].scatter(x_fail, y_fail, s=1, c='red', alpha=0.1, zorder=1) if write_pass: x_pass, y_pass = zip(*write_pass) axes_write[dq_index].scatter(x_pass, y_pass, s=1, c='green', alpha=0.5, zorder=2) # 添加写眼图标注 write_text = f"最大眼宽: {write_width:.3f} UI\n最大眼高: {write_height:.3f} V" axes_write[dq_index].annotate( write_text, xy=(0.98, 0.02), xycoords='axes fraction', fontsize=9, ha='right', va='bottom', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8) ) # 绘制读眼图 if read_fail: x_fail, y_fail = zip(*read_fail) axes_read[dq_index].scatter(x_fail, y_fail, s=1, c='red', alpha=0.1, zorder=1) if read_pass: x_pass, y_pass = zip(*read_pass) axes_read[dq_index].scatter(x_pass, y_pass, s=1, c='green', alpha=0.5, zorder=2) # 添加读眼图标注 read_text = f"最大眼宽: {read_width:.3f} UI\n最大眼高: {read_height:.3f} V" axes_read[dq_index].annotate( read_text, xy=(0.98, 0.02), xycoords='axes fraction', fontsize=9, ha='right', va='bottom', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8) ) # 设置公共轴属性 for ax, direction in [(axes_write[dq_index], '写'), (axes_read[dq_index], '读')]: ax.set_title(f'DQ{dq_index} {direction}眼图', fontsize=12) ax.set_xlabel('延迟 (UI)', fontsize=10) ax.set_ylabel('电压 (V)', fontsize=10) ax.set_xlim(0, 4 if direction == '写' else 2) ax.set_ylim(0, avddq) ax.grid(True, linestyle='--', alpha=0.6) ax.legend(handles=legend_elements, loc='upper right', fontsize=9) ax.tick_params(axis='both', which='major', labelsize=9) # 调整布局 fig_write.tight_layout(rect=[0, 0, 1, 0.96]) fig_read.tight_layout(rect=[0, 0, 1, 0.96]) # 文件路径处理 log_dir = os.path.dirname(log_path) or os.getcwd() timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") log_filename = os.path.basename(log_path) log_name = log_filename.rsplit('.', 1)[0] if '.' in log_filename else log_filename # 构建输出文件路径 write_filename = os.path.join(log_dir, f"{log_name}_ddr_write_eye_{timestamp}.png") read_filename = os.path.join(log_dir, f"{log_name}_ddr_read_eye_{timestamp}.png") # 保存图像 fig_write.savefig(write_filename, dpi=300, bbox_inches='tight') fig_read.savefig(read_filename, dpi=300, bbox_inches='tight') # 关闭图像释放内存 plt.close(fig_write) plt.close(fig_read) # 打印结果 print(f"写眼图已保存至: {write_filename}") print(f"读眼图已保存至: {read_filename}") return write_filename, read_filename, raw_data_file # ===================================================== # 主函数(修改:包含原始数据导出) # ===================================================== def main(): """主函数,程序入口点""" print("=" * 50) print("DDR眼图生成器(带原始数据导出)") print("=" * 50) # 用户输入 data_rate = float(input("请输入DataRate (Mbps/Pin): ")) avddq = float(input("请输入AVDDQ电压值 (V): ")) # 归一化点输入处理 while True: norm_input = input("请输入归一化点(十六进制值,如0x40或40): ").strip() if not norm_input: print("错误: 输入不能为空,请重新输入") continue try: if norm_input.startswith(("0x", "0X")): hex_str = norm_input[2:] else: hex_str = norm_input normalization_point = int(hex_str, 16) break except ValueError: print(f"错误: '{norm_input}' 不是有效的十六进制数,请重新输入") # 日志文件路径输入 while True: log_path = input("请输入日志文件路径: ").strip() if not os.path.exists(log_path): print(f"错误: 文件 '{log_path}' 不存在,请重新输入") else: break # 获取绝对路径 log_path = os.path.abspath(log_path) # 读取文件内容 log_content = robust_read_file(log_path) if log_content is None: print("无法读取日志文件") return # 尝试生成眼图 try: # 调用眼图生成函数(返回三个值) write_file, read_file, raw_data_file = plot_eye_diagrams( log_content, data_rate, avddq, log_path, normalization_point ) print("\n眼图生成成功!") print(f"原始数据文件: {raw_data_file}") except Exception as e: print(f"眼图生成失败: {e}") # Python特殊检查 if __name__ == "__main__": main()
最新发布
07-31
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值