Procmail 可以轻松地在条件下运行外部命令并对其退出状态做出反应。如何让您的特定 SQL 客户端设置其退出代码将取决于您使用的是哪一个;例如,当查询产生空结果集时,它的man
页面可能会显示一个选项以使其退出并出现错误?或者编写一个外壳包装器来查找空输出。
一个复杂的问题是 Procmail(或者更确切地说,配套实用程序)可以轻松地从例如标题formail
中提取字符串;From:
但是您想将其减少到仅电子邮件终端。这是一个很常见的任务,很容易找到一个固定的解决方案——生成一个回复,然后从中提取To:
地址(原文如此!)。
FROM=`formail -rtzxTo:`
:0
* FROM ?? ^(one@example\.com|two@site\.example\.net|third@example\.org)$
{
:0
* ? yoursql --no-headers --fail-if-empty-result \
--batch --query databasename \
--eval "select yada yada where address = '$FROM'"
{ }
:0E
/dev/null
}
第一个条件检查变量并在它包含一个地址时成功(我的原始答案只是具有.
匹配的正则表达式,如果字符串包含至少一个字符,任何字符;我不相信这实际上是必要或有用的;那里应该是没有办法为From:
空的)。如果为真,Procmail 进入大括号;如果没有,它们将被跳过。
大括号内的第一个配方运行一个外部命令并检查其退出代码。我想象您的 SQL 客户端被调用yoursql
,并且它具有关闭人类友好格式(表头等)和直接从特定数据库上的命令行运行查询的选项。我们使用双引号,以便 shellFROM
在运行此命令之前插入变量(也许有一种更安全的方法来传递可能包含 SQL 注入尝试的字符串变量,--variable from="$FROM"
然后在查询中使用该变量?见下文。)
如果没有直接设置退出代码的选项,但是可以确保标准输出在没有结果的情况下完全为空,将命令传递给grep -q .
将产生正确的退出代码。在更复杂的情况下,可能会编写一个简单的 Awk 脚本来识别空结果集并相应地设置其退出状态。
从https://www.postgresql.org/docs/current/app-psql.html抓取信息
,
如何在 psql 中使用脚本变量?,
从 psql和您的问题中生成一个空输出,我最终尝试在以下中实现它psql
;但由于我没有要测试的 Postgres 实例,也没有关于您的数据库模式的任何信息,所以这充其量只是近似值。
* ? psql --no-align --tuples-only --quiet \
--dbname=databasename --username=something --no-password \
--variable=from="$FROM" \
--command="select email from users where email = :'from'" \
| grep -q .
(我们仍然不能在 SQL 查询周围使用单引号,以完全保护它免受 shell 的影响,因为 Postgres 坚持在 周围使用单引号:'from'
,而 shell 没有提供将文字单引号嵌入单引号内的工具。)
周围的 Procmail 代码应该是不言自明的,但无论如何。在大括号内的第一个配方中,如果条件为真,则其操作行中的空大括号是无操作的;下一个配方上的E
标志是一个条件,仅当前一个配方上的任何条件失败时才为真。这是避免使用大量否定的常用习语;也许查一下“德摩根定律”。最终结果是,/dev/null
如果第一个配方中的任何一个条件失败,我们就会通过将消息传递给它来丢弃消息;否则,我们只是简单地传递它,Procmail 最终会将它传递到它的默认目的地。
配方已根据您对问题的更新进行了重构;也许现在用前面psql
的 a否定退出代码会更有意义:!
FROM=`formail -rtzxTo:`
:0
* FROM ?? ^(one@example\.com|two@site\.example\.net|third@example\.org)$
* ! ? psql --no-align --tuples-only --quiet \
--dbname=databasename --username=something --no-password \
--variable=from="$FROM" \
--command="select email from users where email = :'from'" \
| grep -q .
/dev/null
切线地,也许注意到 Procmail 的语法如何利用前导?
或加倍??
在正则表达式中无效的事实。所以解析器可以明确地告诉这些条件不是正则表达式;他们将变量与 之后的正则表达式进行比较??
,或分别检查外部命令的退出状态。Procmail 中还有一些其他类似的特殊条件;可以说,所有这些都相当晦涩难懂。
shell 脚本的新手还应该注意到,每个 shell 命令管道都有两个不同的结果:打印在标准输出上的任何内容,以及与此完全分开的退出代码,它显示命令是否成功完成。(通常,零退出状态表示成功,其他任何内容都是错误。例如,grep
如果找到至少一个匹配项,则退出状态为 0,如果没有,则通常为其他非零退出代码传入了无效的正则表达式,或者您没有读取输入文件的权限等)
有关更多详细信息,也许还可以参见http://www.iki.fi/era/procmail/,它有一个旧的“迷你常见问题解答”,其中涵盖了这里的几个主题,以及一个用于查找详细信息的“快速参考”句法。
我对 Virtualmin 不熟悉,但https://docs.virtualmin.com/Webmin/PostgreSQL_Database_Server显示了如何设置 Postgres 并按照https://docs.virtualmin.com/Webmin/Procmail_Mail_Filter我猜你会想要使用将此代码放入include
文件中的选项。