Python Ubuntu仓库同步脚本卡在条件判断处无输出,求排查
问题排查与修复
你的脚本卡在条件判断环节无输出,核心问题出在subprocess的使用方式错误和逻辑判断失误,以下是具体问题和修复方案:
主要问题点
1. subprocess.Popen 未等待进程完成,且重复读取流导致内容丢失
- 使用
Popen执行命令后,进程是异步运行的,直接调用stdout.read()/stderr.read()可能会因为进程未结束而阻塞,或者读取到空内容。 - 并且
stdout/stderr的流只能被读取一次,第一次读取后,第二次再读就会返回空字符串,导致判断逻辑失效。
2. 错误判断逻辑完全错误
cmd.stderr.read().strip() is not None这个条件永远为True,因为即使stderr没有内容,strip()后得到的是空字符串"",而空字符串不等于None。- 你在条件里先读了一次
stderr.read().strip(),之后再调用cmd.stderr.read().strip()时,流已经被读完,会输出空内容,导致你误以为脚本卡住。
3. 未处理进程返回码
- 单纯读取stderr无法准确判断命令是否执行成功,应该结合进程的返回码
returncode来判断。
修复后的代码
# -*- coding:utf-8 -*- # 2022-07-29 # 同步指定的ubuntu apt仓库到本地 # Synchronize the specified Ubuntu apt repository to the local import subprocess import os rsync_server = 'rsync://rsync.mirrors.ustc.edu.cn/' rsync_dest_major_dir = '/opt/mirror/' # 确保路径末尾有/ if not rsync_server.endswith('/'): rsync_server += '/' if not rsync_dest_major_dir.endswith('/'): rsync_dest_major_dir += '/' # 检查rsync是否存在,使用subprocess.run同步执行 try: result = subprocess.run('which rsync', shell=True, text=True, capture_output=True, check=True) except subprocess.CalledProcessError: print('rsync command not found, please ensure the command is available') exit(1) sync_list = [ 'ubuntu/dists/focal/', 'ubuntu/dists/focal-backports/', 'ubuntu/dists/focal-proposed/', 'ubuntu/dists/focal-security/', 'ubuntu/dists/focal-updates/', 'ubuntu/dists/bionic/', 'ubuntu/dists/bionic-backports/', 'ubuntu/dists/bionic-proposed/', 'ubuntu/dists/bionic-security/', 'ubuntu/dists/bionic-updates/', 'ubuntu/dists/xenial/', 'ubuntu/dists/xenial-backports/', 'ubuntu/dists/xenial-proposed/', 'ubuntu/dists/xenial-security/', 'ubuntu/dists/xenial-updates/' ] for repo_path in sync_list: rsync_dest_full_dir = rsync_dest_major_dir + repo_path if not os.path.exists(rsync_dest_full_dir): os.makedirs(rsync_dest_full_dir, mode=0o755) # 构造rsync命令,注意:-n是 dry-run 模式,仅模拟同步,实际不会传输文件,正式使用可以去掉 cmd_str = f'rsync -avzPn {rsync_server}{repo_path} {rsync_dest_full_dir}' result = subprocess.run(cmd_str, shell=True, text=True, capture_output=True) # 判断命令执行是否成功 if result.returncode != 0: print(f'同步失败: {repo_path}') print(f'错误信息: {result.stderr.strip()}') exit(2) else: print(f'同步完成: {repo_path}') print(f'输出信息: {result.stdout.strip()}')
关键修改说明
- 改用
subprocess.run():同步执行命令,等待进程完成后获取输出,避免异步导致的阻塞或读取空内容问题。 - 使用
capture_output=True:统一捕获stdout和stderr,避免重复读取流的问题。 - 基于返回码判断执行结果:
returncode为0表示命令执行成功,非0表示失败,比单纯读取stderr更可靠。 - 移除重复读取流的操作:一次性获取stdout和stderr的内容,避免流被耗尽导致的空输出。
- 注释说明
-n参数:提醒你这是模拟同步模式,正式使用时可以去掉-n来实际同步文件。
内容的提问来源于stack exchange,提问作者virgil710
相关产品推荐
相关产品推荐

