
在自动化脚本和系统管理任务中,经常需要从Python程序中调用外部命令行工具。然而,标准subprocess模块在处理长时间运行的命令输出时,若要实现逐行实时读取并为每行添加时间戳,会面临一些挑战。直接通过shell管道(如| while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done)来处理,虽然在shell中可行,但将其无缝集成到Python的subprocess调用中并保持其可移植性,往往不够直观和灵活。
为了优雅地解决这一问题,我们可以利用pexpect库来模拟终端交互并捕获子进程的输出,同时结合Python内置的logging模块来自动处理时间戳的添加和日志记录。这种方法不仅功能强大,而且代码简洁、易于维护。
pexpect是一个Python模块,用于控制其他程序、模拟终端并捕获其输出。它非常适合处理需要交互的命令行工具,或者像本例中这样需要实时逐行读取输出的场景。与subprocess模块相比,pexpect提供了更细粒度的控制,例如等待特定模式的输出、发送输入等。
Python的logging模块是一个功能完善的日志记录框架。它支持多种日志级别、输出目的地(文件、控制台等)以及自定义日志格式。其中,日志格式的配置是实现自动添加时间戳的关键。
立即学习“Python免费学习笔记(深入)”;
以下是实现带时间戳的子进程输出的完整代码示例及详细解析:
#! /usr/bin/env python
import logging
import pexpect
import sys
# 1. 配置日志系统
# 设置日志的基本配置,包括输出文件名、编码、日志格式和最低记录级别。
# %(asctime)s 会自动插入当前时间戳。
# %(levelname)-8s 会插入日志级别(如 INFO, DEBUG),并左对齐,占用8个字符。
# %(message)s 会插入实际的日志内容。
logging.basicConfig(
filename='ts.log', # 日志将写入的文件
encoding='utf-8', # 文件编码
format='%(asctime)s %(levelname)-8s %(message)s', # 日志格式
level=logging.DEBUG # 记录所有DEBUG及以上级别的日志
)
# 也可以同时将日志输出到控制台,方便实时查看
# console_handler = logging.StreamHandler(sys.stdout)
# console_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s %(message)s'))
# logging.getLogger().addHandler(console_handler)
def run_command_with_timestamp_logging(cmd: str):
"""
执行给定的命令行命令,并将子进程的输出逐行记录到日志文件中,
每行自动添加时间戳。
Args:
cmd (str): 要执行的命令行字符串。
"""
logging.info(f"Executing command: '{cmd}'") # 记录即将执行的命令
try:
# 使用 pexpect.spawn 启动命令。
# spawn 会模拟一个终端,允许我们逐行读取输出。
# encoding="utf-8" 指定了子进程输出的编码。
p = pexpect.spawn(cmd, encoding="utf-8")
# 循环读取子进程的每一行输出
# walrus operator (:=) 在 Python 3.8+ 中可用,使代码更简洁
while line := p.readline():
# 将读取到的行(去除首尾空白,特别是换行符)作为日志消息记录。
# logging 模块会根据配置自动添加时间戳和日志级别。
logging.info(line.strip())
# 等待子进程结束,并获取其退出状态码
p.wait()
logging.info(f"Command '{cmd}' finished with exit code: {p.exitstatus}")
except pexpect.exceptions.TIMEOUT:
logging.error(f"Command '{cmd}' timed out.")
except pexpect.exceptions.EOF:
logging.error(f"Command '{cmd}' finished unexpectedly (EOF reached).")
except Exception as e:
logging.exception(f"An error occurred while running command '{cmd}': {e}")
# 示例用法
if __name__ == "__main__":
print("Running 'ls -l' command and logging output to ts.log...")
run_command_with_timestamp_logging("ls -l")
print("\nRunning 'docker build .' (if docker is installed) and logging output to ts.log...")
# 注意:如果docker未安装或命令长时间无输出,可能需要调整pexpect的超时设置
run_command_with_timestamp_logging("docker build .")
print("\nRunning 'ping -c 5 google.com' and logging output to ts.log...")
run_command_with_timestamp_logging("ping -c 5 google.com")
print("\nCheck 'ts.log' for the timestamped output.")logging.basicConfig(...):
run_command_with_timestamp_logging(cmd: str) 函数:
通过巧妙地结合pexpect库的进程交互能力和logging模块的强大日志管理功能,我们能够以一种高效、健壮且Pythonic的方式,为Python子进程的输出添加自动时间戳。这种方法不仅提升了日志的可读性和可追溯性,也为处理更复杂的子进程交互场景奠定了基础,是Python自动化脚本和系统管理任务中的一个实用技巧。
以上就是在Python中运行子进程并为输出添加时间戳的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号