如何将输出从一个进程传递到另一个进程,但仅在第一个进程具有输出时才执行?


23

如果从中输出,我如何才能将此命令重写为仅电子邮件mailq | grep

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email

甚至可以单行吗?

请参阅检查管道是否为空,如果不是比发送电子邮件更一般的情况,请对数据运行命令


Answers:


19

我认为您将必须使用一个临时文件来执行此操作,以便&&仅当grep返回退出状态(表明其具有以下匹配项)时,才可以使用运算符来运行mail命令:

TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE"

如果您不介意临时文件停留在某个地方并且可以使用静态名称,则可以跳过特殊的命名和删除内容:

 mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep

编辑:看到格伦的答案后,我对此进行了更多$()的尝试,显然使用语法分配了变量将返回命令的退出代码,因此您可以跳过他用于字符串长度的测试,而改用它。这是一个命令中的全部内容:

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data"

编辑2:看到西蒙的答案后,我签出了我的mail程序。默认情况下,它的行为方式与他描述的方式不同,但是有一个选项。从手册页:

-E如果外发消息的第一个或唯一消息部分不包含任何文本,请不要发送该消息,而应将其静默丢弃,从而在程序启动时有效地设置了skipemptybody变量。这对于从cron(8)启动的脚本发送消息很有用。

使之成为可能:

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email

1
协作的力量!!
格伦·杰克曼

3
我建议通过将最佳解决方案移至顶部,可以使此答案更好。
Mark Booth,

@Wildcard鉴于输入参数mktemp不会返回需要引用的内容,因此该编辑是不必要的。
卡列布

2
我知道。你是谁困扰明白,报价为数不多有时是必要的(故意省略了它们)。但是,除非您明确希望调用,否则默认值为引号glob(split(var))。您无需在此处进行字分割或文件扩展,所以不需要它们。另外,我们需要在此网站上显示正确的方法
通配符

@Wildcard公平。我通常会奔跑zsh,除非出现此类情况,否则在这种情况下实际上不会出现混乱或单词分裂的情况,但出于此处的答案,并且不知道目标环境引用不正确,这是可以的。
卡列布

11

实用程序ifne专门用于此目的:如果标准输入不为空,则运行命令。

mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email

ifne命令是moreutils软件包的一部分,被称为“越来越多的Unix工具集合,在Unix 成立之初,没人想过要写。”


8

您可以将输出保存在变量中,然后在字符串的长度不为零的情况下调用mail命令。

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5)
[[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data"

对于一行,将两个命令用分号连接起来。


1
使用变量而不是临时文件的道具。这让我开始思考退出代码从执行变量分配的命令那里去了,显然它被传递了!请参阅我的最新答案
卡雷布(Caleb)

7

mail与该-E选项一起使用。在我的Mac上,MAIL(1)说该-E标志不会发送带有空正文的电子邮件。

-E不要发送带有空正文的消息。这对于cron(8)脚本中的管道错误很有用。

在Mac上,我运行了以下测试。请注意该文件file_does_exist确实存在,但该文件file_does__not_exist不存在。

这会向我发送电子邮件:

$ ls file_does_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org

这不是。请注意,该命令ls file_does_not_exist | egrep ...不会产生任何输出。

$ ls file_does_not_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org
ls: file_does_not_exist: No such file or directory

迦勒击败了你。
吉尔斯(Gilles)'所以

1
他只击败了我4.75小时:)。我在他冗长的回答中错过了这个细节。
Stefan Lasiewski 2011年

5

在这种情况下,如果您mail支持该-E选项,则只需使用它即可。在一般情况下,您可以尝试读取一个字符。如果存在,则启动后处理命令,并从文件的其余部分中输​​入该字符。

pipe_if_not_empty () {
  a=$(dd bs=1 count=1 2>/dev/null; echo .)  # read at most one character
  if [ "$a" != "." ]; then                  # if there were two characters,
    { printf %s "${a%.}";                   # then output the first character
      cat; } |                              # and the rest of the input   
    "$@"                                    # into the specified program
  fi
}

mailq | egrep 'rejected|refused' -A 5 -B 5 |
pipe_if_not_empty mail -s 'dd' email@email

请注意的有用用法cat。加入的echo .品牌即使在输入第一个字符是换行该功能的工作(记住,$(…)构建去掉终端新行)。

对于大多数shell(据我所知,除zsh以外的任何东西),如果文件以空字符开头,则此代码将认为它为空。剩下的解决方法是作为练习供读者阅读。(提示:od在第一个子shell中使用并printf打印第一个字节。)(解决方案:如何检查管道是否为空)如果文件开头的字节不是当前的有效字符,则可能会遇到相同的问题语言环境 使用来运行此代码更容易解​​决LC_ALL=C


+1是荒谬的,但在另一种情况下可能有用:)出于好奇,为什么注入并测试点而不是测试空字符串?如果输入以点开头,这不会带来问题吗?使用read帮助可以简化此过程吗?
卡莱布

@Caleb:是的,我应该提到我是在回答标题中的问题,而不是针对特定情况。有关点的说明,请参见我的编辑。我不认为您可以read在可移植的sh中将空的第一行与空文件区分开(在bash,ksh或zsh中可能如此)。
吉尔(Gilles)'所以


1

最近,我了解ifnemoreutils软件包中一部分的命令名称。在哪里可以使用它来解决此特定问题。

ifne-如果标准输入不为空,则运行命令

手册页中的示例

EXAMPLE
       find . -name core | ifne mail -s "Core files found" root

0

您可以使用test -s /dev/stdin检查您是否有任何输出来重写命令mailq | grep

- mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email
+ mailq | egrep 'rejected|refused' -A 5 -B 5 | (test -s /dev/stdin && cat) | mail -s 'dd' email@email
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.