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

如何用Bash提取.eml指定短语后至空行文本并处理=结尾软换行

问题根因

你写的脚本在测试txt上正常、真实eml上失效,两个问题的本质原因都是没有适配eml文件的格式特性:

  • 空行停止逻辑失效:真实eml的段落分隔空行往往不是纯零字符空行,要么带Windows换行残留的\r(CR回车符,用cat -v查看会显示为^M),要么带不可见的空格/制表符,你写的/^$/正则只能匹配完全无任何字符的行,自然识别不到这类分隔行,会一直输出到文件末尾。
  • QP软换行合并失效:一是行尾的=前后可能夹带\r隐藏字符,导致你判断/=$/的正则匹配不到;二是如果把软换行合并和内容提取的顺序写反,没先合并拆分的行就做匹配,逻辑会直接失效。另外macOS自带的sed/awk都是BSD版本,和Linux上的GNU版本语法有差异,照搬Linux教程的写法也会出异常。
可用实现方案

两个方案均适配macOS 12.4自带运行环境,无需额外安装依赖。

方案1:BSD工具链Shell脚本(优先bash兼容)

脚本先统一剔除隐藏回车符,优先完成QP软换行合并,再做关键词匹配和段落提取,空行识别兼容带不可见空白的场景。

#!/bin/bash
# 适配macOS 12.4 自带bash 3.2/BSD工具链
if [ $# -lt 2 ]; then
    echo "用法: $0 <搜索关键词> <eml文件路径1> [eml文件路径2...]"
    exit 1
fi

KEYWORD="$1"
shift

for eml_file in "$@"; do
    echo "===== 处理文件: $eml_file ====="
    # 第一步:删除所有CR回车符,解决隐藏字符问题
    tr -d '\r' < "$eml_file" | awk -v kw="$KEYWORD" '
    BEGIN {
        capture = 0
        buffer = ""
    }
    {
        # 处理QP软换行拼接
        if (buffer != "") {
            cur_line = buffer $0
            buffer = ""
        } else {
            cur_line = $0
        }
        # 行尾以=结尾则存入缓冲区,等待下一行拼接
        if (sub(/=$/, "", cur_line)) {
            buffer = cur_line
            next
        }

        # 软换行合并完成后处理内容提取
        if (capture == 0) {
            if (index(cur_line, kw) > 0) {
                capture = 1
            }
            next
        } else {
            # 匹配到全空白行则停止捕获
            if (cur_line ~ /^[[:space:]]*$/) {
                capture = 0
                next
            }
            print cur_line
        }
    }
    END {
        # 输出缓冲区剩余的未处理内容
        if (buffer != "" && capture == 1) {
            print buffer
        }
    }
    '
done

方案2:Python脚本(容错性更高,适合大批量处理)

用Python标准库直接处理QP解码,不用手动写换行合并逻辑,对非标准编码的eml兼容性更好。

#!/usr/bin/env python3
import sys
import quopri
import os

def extract_from_eml(keyword, file_path):
    print(f"===== 处理文件: {file_path} =====")
    with open(file_path, 'rb') as f:
        raw = f.read()
        # 自动解码QP格式、合并软换行
        decoded = quopri.decodestring(raw).decode('utf-8', errors='ignore')
        # 统一换行符格式
        lines = decoded.replace('\r\n', '\n').replace('\r', '\n').split('\n')
    
    capture = False
    for line in lines:
        if not capture:
            if keyword in line:
                capture = True
            continue
        # 遇到空行停止输出
        if not line.strip():
            capture = False
            break
        print(line)

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print(f"用法: {sys.argv[0]} <搜索关键词> <eml文件路径1> [路径2...]")
        sys.exit(1)
    kw = sys.argv[1]
    for fpath in sys.argv[2:]:
        if os.path.isfile(fpath):
            extract_from_eml(kw, fpath)
使用说明
  • 把脚本保存到本地,shell脚本存为extract_eml.sh,Python脚本存为extract_eml.py,执行chmod +x 脚本文件名添加执行权限
  • 调用示例:提取目录下所有eml中包含「报销明细」关键词的对应段落,结果保存到result.txt:
    • Shell版执行:./extract_eml.sh "报销明细" ./你的eml存放目录/*.eml > result.txt
    • Python版执行:./extract_eml.py "报销明细" ./你的eml存放目录/*.eml > result.txt
  • 如果遇到中文乱码,把Python脚本里decode('utf-8'的utf-8替换为gb18030即可适配国内部分邮件客户端的编码格式
  • 单批次处理上千个eml文件时,Python版的处理速度比Shell版快3~5倍

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:57:33