我们有一个非常手动和基本的电子邮件取消订阅系统,我正在尝试将其自动化。有一个文件包含要取消订阅的电子邮件地址列表,该文件的格式是每行有一个电子邮件地址,因此我猜应该可以使用 cat 。
在同一个文件夹中,有数千个“.eml”文件(原始电子邮件文件)批量发送到sendmail。生成这些 .eml 文件的成本很高,因此我们将它们保存在一个文件夹中并定期发送,直到有人取消订阅。我想做的是编写一个 bash 脚本,循环遍历文件中的所有电子邮件地址,在每个电子邮件地址的文件夹上运行 grep,然后删除 grep 匹配的文件。
由于我的 Unix 技能非常有限,我正在尝试将其作为可重用的 bash 脚本(带有循环等),以便提高我的 Unix 技能
答案1
一个简单的方法是(假设 GNU 实用程序):
grep -FZlw -f address.list -- *.eml | xargs -r0 rm -f --
或者相同但具有 GNU 实用程序支持的长选项:
grep --fixed-strings \
--null --files-with-matches \
--word-regexp \
--file address.list \
-- *.eml |
xargs --no-run-if-empty --null \
rm --force --
但这会在找到地址时删除文件任何地方在文件中,无论是在From:
、To:
、Cc:
、Reply-To
标题中,还是在电子邮件正文或附件中。
此外,如果address.list
包含 ,[email protected]
也会删除[email protected]
和 的电子邮件[email protected]
。
address.list
这还假设文件中的电子邮件地址格式相同(大小写相同,无 MIME 编码)eml
。
如果您确切地知道电子邮件的格式,例如,如果它们总是包含一次且仅一次出现这样的行:
To: [email protected]
其中[email protected]
格式与您的完全相同address.list
,那么您可以执行以下操作:
sed 's/^/To: /' address.list | grep -xZFlf - -- *.eml | xargs -r0 rm -f --
哪个会更可靠。
而不是将address.list
作为列表传递字为了在文件中的任何位置找到,我们首先使用s
tream ed
itor 命令转换搜索列表,为每行添加前缀,"To: "
以便固定串模式变为并使用/ (而不是/ )来匹配行 e 的完整内容。 (所以例如不匹配)。To: [email protected]
-x
--line-regexp
-w
--word-regexp
x
To: [email protected]
Reply-To: [email protected].eu
如果您不想删除文件,而是想检查要删除的文件的标头,请替换rm -f
为上面的内容。grep -H '^To:'
To:
答案2
使用以下脚本:
#!/bin/bash
email_dir=./emails
unsubscribe_file=./emails/unsubscribe.txt
while IFS= read -r email _; do
files=($(grep -rni "$email" "$email_dir" | grep -v 'unsubscribe.txt'))
if ((${#files[@]}>1)); then
printf '%s\n' "warning: Found multiple files for: $email" "${files[@]}" >&2
elif ((${#files[@]}==1)); then
rm "$(echo "${files[0]}" | awk -F\: '{print $1}')"
fi
done < "$unsubscribe_file"
email_dir
应设置为包含电子邮件的目录的路径
unsubscribe_file
应设置为包含要取消订阅的电子邮件的文件的路径
while 循环将读取取消订阅文件,并为每一行将变量设置email
为第一个字段(这应该是唯一的字段,但_
如果存在,将捕获任何剩余的字段)
我们将在该电子邮件地址的目录的所有文件中执行 grep email_dir
(这也将返回取消订阅文件,因此我们使用 grep 将其从结果中删除。如果它不在同一目录中,那将是理想的选择。 但请务必更改grep -v 'unsubscribe.txt'
以反映您取消订阅文件的实际名称)
我们将这些结果设置为一个数组,以防有多个结果。在这种情况下,它将抛出错误并且不会删除任何内容。如果只有 1 个结果,我们将从 grep 输出中提取文件名并将其删除。