【问题标题】:bash script - fetch only unique domains from email list to variablebash 脚本 - 仅从电子邮件列表中获取唯一域到变量
【发布时间】:2019-02-12 01:13:41
【问题描述】:

我是 bash 新手,在理解如何完成此操作时遇到问题。

检查所有“收件人:”字段电子邮件地址域并将所有唯一域列出到变量以将其与域进行比较。

我通过使用

获得“发件人地址”域
grep -m 1 "From: " filename | cut -f 2 -d '@' | cut -d ">" -f 1

读取存储在文件filename中的邮件时。

对于“to address”域,可以有多个 To: 地址和多个域。我不确定如何从“到地址字段”获取唯一域。

地址行示例如下:

To: user@domain.com, user2@domain.com, 
    User Name <sample@domaintest.com>, test@domainname.com
grep -m 1 "^To: " filename | cut -f 2 -d '@' | cut -d ">" -f 1

但有不同格式的电子邮件。所以我不确定grep是否正确,或者我是否应该搜索awk或其他东西。

我需要从“收件人:”字段电子邮件地址/地址获取唯一域列表到 bash 脚本中的变量。

上述示例所需的输出:

domain.com,domaintest.com,domainname.com

【问题讨论】:

  • 使用 GNU grep:grep -m 1 "^To: " filename | grep -Po '@\K[^, &gt;]+'?
  • @Cyrus 有效,但显然“To:”字段分两行。示例中的“用户名”部分已转到实际电子邮件文件中的下一行,而我认为 grep 只检查一行?所以它只有前 2 个电子邮件 ID 的 2 个域。
  • 请将该示例输入的所需输出添加到您的问题中。
  • 我添加了一个输出请求,感谢@Cyrus的帮助

标签: regex bash


【解决方案1】:

如果您一心想要使用面向行的实用程序来执行此操作,那么 Procmail 发行版中有一个实用程序 formail 可以在一定程度上为您标准化。

bash$ formail -czxTo: <<\==test==
> From: me <sender@example.com>
> To: you <first@example.org>,
>    them <other@example.net>
> Subject: quick demo
>
> Very quick, innit.
> ==test==
first@example.org,    other@example.net

这样你就有了输入,你实际上可以传递给grep或Awk ...或sed

fromdom=$(formail -czxTo: <message | tr ',' '\n' | sed 's/.*@//')

From: 地址不会被formail -czxFrom: 标准化,但您可以使用一个巧妙的技巧:让formail 生成对From: 地址的回复,然后从中提取To: 标头。

todoms=$(formail -rtzcxTo: <message | sed 's/.*@//')

更详细地说,-r 说要创建一个新的回复给给你发信 message 的人,然后我们在 上做 -zcxTo:

(-t 选项可能会也可能不会做你想做的事。在这种情况下,我可能会省略它。http://www.iki.fi/era/procmail/formail.html 有(模糊的)文档说明它的作用;另请参阅http://www.iki.fi/era/procmail/mini-faq.html#group-writable 之前的部分并且对于笨拙的链接感到抱歉——似乎没有一个好的页面内部锚可以链接到。)

【讨论】:

  • 我会接受这个作为答案,因为它符合我的要求,但阅读你的想法。我们决定改为在 php 上完成所有 bash 脚本部分。所以我现在必须以不同的方式编写所有内容。感谢您的帮助。
  • PHP 并不是我的首选,但祝你好运! (-:
【解决方案2】:

电子邮件地址规范化很棘手,因为有很多变体可供选择。

From: Elvis Parsley <king@graceland.example.com>
From: king@graceland.example.com
From: "Parsley, Elvis" <king@graceland.example.com> (kill me, I have to use Outlook)
From: "quoted@string" <king@graceland.example.com> (wait, he is already dead)
To: This could fold <recipient@example.net>,
   over multiple lines <another@example.org>

我会转向一种功能更强大的语言,并适当支持解析所有这些格式。我的选择是 Python,尽管你也可以用几行 Ruby 或 Perl 来完成。

email 库在 Python 3.6 中进行了改进,因此假设您至少拥有该版本。 3.6 中新增的email.Headerregistry 类在这里特别方便。

#!/usr/bin/env python3

from email.policy import default
from email import message_from_binary_file
import sys

if len(sys.argv) == 1:
    sys.argv.append('-')

for arg in sys.argv[1:]:
    if arg == '-':
        handle = sys.stdin
    else:
        handle = open(arg, 'rb')

    message = message_from_binary_file(handle, policy=default)
    from_dom = message.get('From').address.domain
    to_doms = set()
    for addr in message.get('To').addresses:
        dom = addr.domain
        if dom == from_dom:
            continue
        to_doms.add(dom)
    print(','.join([from_dom] + list(to_doms)))

    if arg != '-':
        handle.close()

这只是生成一个以逗号分隔的域名列表;您可能还想在 Python 中进行其余的处理,或者更改它以使其以稍微不同的格式打印。

您可以将它保存在一个方便的地方(例如,/usr/local/bin/fromto)并将其标记为可执行文件(chmod 755 /usr/local/bin/fromto)。现在您可以像 grep 等任何其他实用程序一样从 shell 调用它。

【讨论】:

  • 我不认为我可以使用 python,因为这实际上是通过用于 altermime 的后缀内容过滤器完成的。
  • 如果你可以使用 shell 脚本,你可以从那个 shell 脚本调用 Python。请参阅更新的最后一段。
  • 不能从 awk 或其他一些本机命令执行吗?因为调用 python 脚本并将值返回到 shell 脚本会导致更多的时间延迟我觉得。我必须处理收到的邮件并根据邮件进行更改并发送邮件。所以时间成为一个因素。仅在 bash 命令中是不可能的?
  • 没有什么是不可能的,但我不想在 Awk 中重新实现所有漂亮的 Python 库代码(我已经不止一次做过类似的事情,而且总是后悔)。如果 Python 最终能和 Awk 一样快,我不会感到惊讶。
  • 您能否更详细地描述一下您在 Postfix 集成方面想要实现的目标?
猜你喜欢
  • 2018-12-08
  • 1970-01-01
  • 2018-08-28
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-15
  • 2017-06-14
相关资源
最近更新 更多