You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 16:16:03