将多个命令传输到单个命令中,且不等待EOF信号。

3
我该如何将多个命令的标准输出导入到单个命令中?例如:
(cat my_program/logs/log.*;tail -0f my_program/logs/log.0) | grep "filtered lines"

我希望能够在单个命令行上使用管道运行以下所有命令,并且不使用重定向到临时文件(如果可能的话)。有一个小细节意味着我不能使用括号;我希望最后一个命令是尾部喂送,因此我希望在接收到每一行 std-in 后发生 grep - 而不是等待 EOF 信号。
3个回答

8

尝试使用当前的shell而不是子shell:

{ cat file1; tail -f file2; } | grep something

分号在右花括号前是必须的。

我同意这是一个无意义的使用新 shell 的方式,可能会导致输出在等待 EOF 时被缓冲。但我之前也尝试过这种方法,结果一直等待 EOF,所以这不是唯一的原因。我很惊讶在命令行中没有简单的方法来做到这一点。 - ChrisN
好的,tail -f永远不会给你EOF,那么你为什么期望它呢?grep在没有EOF的数据流上操作是可以的。 - glenn jackman
@glennjackman 我使用了上面的代码来展示我需要做什么,我知道当你使用 tail -f 命令时它不起作用,但问题不在于 grep,因为 tail -0f my_program/logs/log.0 | grep "filtered lines" 是可以工作的。所以我需要另一种方法来连接 cat my_program/logs/log.*tail -0f my_program/logs/log.0,这样我就需要另一种方式来等待 EOF。 - ChrisN

1
如果命令不必并行执行,则可以使用cat将输出统一为单个连续流,如下所示:
tail -0f log.0 | cat - log.* | grep "filtered lines"

神奇的部分是 cat 命令中的 - 参数;它告诉 cat 命令将标准输入添加到输入列表中(在这种情况下,其他输入是日志文件),以进行连接。


很遗憾,这不起作用,因为它想把日志放在进程结束时的尾部反馈之后。计划是让grep运行所有日志“cat log.*”,然后轮询任何新添加的内容,以执行相同的操作“tail -0f log.0”。 我会分别在每个上运行grep,但是grep只代表一系列命令中的一个管道,因此我担心在cat和tail -0f之间添加到此详细日志的任何内容都将丢失。 感谢Bruce的聪明建议。 - ChrisN
你考虑过使用命名管道吗?运行一个包含循环的脚本,从fifo中读取并通过你的过滤器进行输出。然后,你可以随时将数据放入fifo中。例如,cat log. > /path/to/pipe* 然后跟着 tail -0f log.0 > /path/to/pipe - itsbruce
不,我没有考虑过那个。当用户发送 SIGINT 时,需要进行一些整理工作(即删除 FIFO),但我想我可以使用 trap 命令来完成。这可能是一个可行的方法...再次感谢你,Bruce! - ChrisN

0

好的,我有一个凌乱的解决方案(它是一个脚本 - 不幸的是这对于命令行来说不实用):

#!/bin/bash  

ProcessFIFO(){
    while [[ -p /tmp/logfifo ]]; do
    grep "filtered lines" < /tmp/logfifo
    done
}
OnExit(){
    rm -f /tmp/logfifo
    echo 'temp files deleted'
    exit
}
    # Create FIFO
    mkfifo /tmp/logfifo
    trap OnExit SIGINT SIGTERM
    ProcessFIFO &

    cat log.* > /tmp/logfifo
    tail -0f log.0 > /tmp/logfifo

我已经使用了@itsbruce建议的FIFO方法,同时我还不得不使用while循环来防止grep在EOF信号处结束:

while [[ -p /tmp/logfifo ]]

我还包含了一个删除FIFO的陷阱:

trap OnExit SIGINT SIGTERM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接