Python中如何通过tail -f监控文件变化并实时交给Python -c处理?

错误的命令:

tail -f case.log | python -c "import sys, json, time; print(json.load(sys.stdin)['type']);"

此命令想要的结果: tail -f 一个文件, awk 或其它命令取到 json, 通过管理交给 python 处理. python 解析 json 并打出需要的字段.

jq 命令可以解决这个问题,不过服务器太多,不好在每台服务上装这个命令。python 却是 linux 都带的,所以舍近求远,看有没其它的解决方法。


Python中如何通过tail -f监控文件变化并实时交给Python -c处理?

17 回复

https://gist.github.com/antonchen/0a3c513e2b09b04e2c60b52f96ccb091

手写的不知道能不能跑,反正是这个思路


这个问题挺有意思,在Linux环境下想用tail -fPython -c联动处理实时日志。直接管道传递是行不通的,因为tail -f会持续输出,而python -c执行完就退出了。

核心思路是让Python脚本自己来充当tail -f的角色,持续读取文件新增内容。用subprocess模块调用tail -f并捕获其标准输出流是最直接的办法。

给你一个即拿即用的代码示例:

import subprocess
import sys

def process_line(line):
    """在这里定义你的处理逻辑"""
    # 示例:打印行并添加前缀
    print(f"[处理]: {line}", end='')
    # 你可以在这里进行任何字符串处理、匹配、写入数据库等操作

def tail_and_process(filename):
    try:
        # 启动tail -f进程
        proc = subprocess.Popen(
            ['tail', '-f', filename],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1  # 行缓冲
        )
        
        print(f"开始监控文件: {filename}")
        print("按 Ctrl+C 停止")
        
        # 持续读取输出
        for line in proc.stdout:
            process_line(line)
            
    except KeyboardInterrupt:
        print("\n监控已停止")
    except FileNotFoundError:
        print(f"错误: 文件 '{filename}' 不存在或tail命令不可用")
    except Exception as e:
        print(f"发生错误: {e}")
    finally:
        if 'proc' in locals():
            proc.terminate()

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("用法: python script.py <filename>")
        sys.exit(1)
    
    tail_and_process(sys.argv[1])

如果你想用一行命令搞定,可以这样封装:

python -c "
import subprocess, sys
with subprocess.Popen(['tail', '-f', sys.argv[1]], stdout=subprocess.PIPE, text=True) as proc:
    for line in proc.stdout:
        print(f'[处理]: {line}', end='')
" your_logfile.log

不过说实话,这种复杂逻辑还是写成独立的.py文件更清晰。上面那个脚本保存为log_monitor.py,然后直接python log_monitor.py /path/to/logfile就行。

简单说就是别指望python -c能持续运行,得用脚本来循环读取。

楼主思路我觉得挺好的啊

如果每行是一个 JSON 对象,可以这样处理,但是在解析前先 readline
如果整个日志是一个 JSON 对象的话,要么把 -f 去掉(因为没有意义),要么用流式的 JSON Parser
不要用 python 写 one-liner,要写 one-liner 用 Perl / Ruby

可行,我干过,现在还在跑,没 WAF 的服务器把 nginx 日志 tail 给 php 脚本

如果只是简单过滤 直接 awk 就好

复杂处理直接整个用 python 实现 tail -f 的功能就好

按行处理的话可以这样,配合 supervisord 可以做 service 用

#!/bin/bash

tail -qFn0 /var/log/sample.log | <br>while read line ; do
echo “$line”
#do whatever you want
done

用 tail -f 和 subprocess 实现过简单解析后推送到下游的脚本,稍微改改应该能满足楼主的需求

https://github.com/iyaozhen/filebeat.py

收下大佬的思路




我的场景,一行一个条日志,其中一小部分是一条 json, 所以会用 awk 或其它切成 json 再管道给后面,不写脚本是因为能一行命令解决的,我就没想写个脚本了。





赞赞赞,可以实现我想要的
<br>tail -qFn0 caselog.log | while read line ; do; python -c "import sys, json, time; print(json.loads('$line')['type']);"; done<br>

tail -f caselog.log | jq ‘.type’ 这样?

用 python 显的太蹩脚了,这时候还不如 perl

tail -qFn0 caselog.log | perl -MJSON -nE ‘say ((decode_json $_)->{type});’


是的 jq 可以解决


是个好思路

这样处理过 apache 日志 =。=

没看懂 tail -qFn0 里的 n0 参数, 为什么要把 line num 设为 0 呢 这样不就一行都不会输出了吗

不要用 Python,直接正则解决。grep awk sed 都行。
在这个场景里除非 JSON 结构很复杂导致必须要解析,否则 Python 是最慢的一环。


同需求


man tail

-n number
The location is number lines.

n0 只显示命令执行后追加到文件中的内容
n100 显示执行命令时最后 100 行,并把命令执行后追加到文件内容显示出来
解释得不好,手动测试一下便知。这里有没有 n0 影响不大,舍弃命令执行前内容可便于观察。


正解

求大神 QQ

回到顶部