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

Java中实现grep -C 5功能:匹配关键词前后5行

刚好之前折腾过Unix4J的类似需求,给你整理两个可行的实现思路和代码示例,帮你实现类似grep -C 5 "Stack trace:"的上下文打印功能:

实现grep上下文打印的Unix4J方案

Unix4J确实没有直接对应-C(上下文行)的现成选项,但我们可以通过组合它的命令或者自定义逻辑来达成目标,下面是两种实用的实现方式:

方法一:组合Unix4J命令实现(适合批量处理文件)

这个方案可以遍历指定目录下的文件,逐个处理并捕获输出,完全贴合你的需求:

import org.unix4j.Unix4j;
import org.unix4j.line.Line;
import java.io.File;
import java.util.List;

public class GrepContextExample {
    public static void main(String[] args) {
        // 配置参数:目标关键词和上下文行数
        String targetKeyword = "Stack trace:";
        int contextLineCount = 5;
        
        // 遍历指定目录下的日志文件(可替换为你需要的路径和文件过滤规则)
        File targetDir = new File("./logs");
        File[] logFiles = targetDir.listFiles(file -> file.isFile() && file.getName().endsWith(".log"));
        
        if (logFiles != null) {
            for (File logFile : logFiles) {
                System.out.println("=== 正在处理文件: " + logFile.getName() + " ===");
                
                // 第一步:找出所有包含关键词的行号(Unix4J中行号从1开始计数)
                List<Long> matchedLineNumbers = Unix4j.grep(targetKeyword, logFile)
                        .toLineStream()
                        .map(Line::getLineNumber)
                        .toList();
                
                // 第二步:针对每个匹配行,提取前后contextLineCount行的内容
                for (long lineNum : matchedLineNumbers) {
                    long startLine = Math.max(1, lineNum - contextLineCount);
                    long endLine = lineNum + contextLineCount;
                    
                    // 用sed命令提取指定行范围的内容,也可以将结果存入变量而非直接打印
                    List<String> contextContent = Unix4j.sed(String.format("%d,%dp", startLine, endLine), logFile)
                            .toStringList();
                    
                    // 输出上下文内容
                    contextContent.forEach(System.out::println);
                    System.out.println("--- 上下文分割线 ---");
                }
            }
        }
    }
}

代码说明

  • 定位匹配行:通过grep找到所有包含关键词的行,再提取每行的行号。
  • 计算上下文范围:对每个匹配行号,计算出需要输出的起始行(防止小于1)和结束行,用sed命令提取对应范围的内容。
  • 批量处理:通过listFiles过滤目标文件,实现遍历处理的需求。

方法二:自定义行处理器(避免重复输出重叠上下文)

如果你的日志中存在关键词密集的情况,第一种方法可能会重复输出重叠的上下文行,这时可以用自定义逻辑先收集所有需要输出的行号,再统一过滤输出:

import org.unix4j.Unix4j;
import org.unix4j.line.Line;
import java.io.File;
import java.util.HashSet;
import java.util.Set;

public class CustomGrepContext {
    public static void main(String[] args) {
        String targetKeyword = "Stack trace:";
        int contextLineCount = 5;
        File targetFile = new File("application.log");
        
        // 先收集所有需要输出的行号,避免重复
        Set<Long> linesToOutput = new HashSet<>();
        
        Unix4j.grep(targetKeyword, targetFile)
                .toLineStream()
                .forEach(line -> {
                    long matchedLineNum = line.getLineNumber();
                    // 将匹配行前后contextLineCount行都加入集合
                    for (long i = Math.max(1, matchedLineNum - contextLineCount); 
                         i <= matchedLineNum + contextLineCount; 
                         i++) {
                        linesToOutput.add(i);
                    }
                });
        
        // 过滤文件内容,只输出目标行
        Unix4j.cat(targetFile)
                .toLineStream()
                .filter(line -> linesToOutput.contains(line.getLineNumber()))
                .forEach(line -> System.out.println(line.getContent()));
    }
}

这种方法先把所有需要输出的行号存入集合,再一次性过滤文件内容,避免了重复处理重叠的上下文区域,效率更高。


内容的提问来源于stack exchange,提问作者Camilo Riviere

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:05:25