我试图弄清楚如何等待命令完成,然后将标准输入通过管道传输到标准输出。我在mac上,但我认为我的问题更多是关于如何等待进程完成和管道输出,然后是与mac有关的任何事情。
我注意到在 mac 上,我可以一起运行几个say
命令,如果我使用操作符将它们连接起来,它们会等待每个短语完全说出,然后再开始下一个&&
。
$ say "stage 1" && say "stage 2"
这就是真正的用例所在——我有一个 bash 脚本,我想让它在它说完之后将它传递给 stdout 。
$ cat /etc/passwd | say_and_pass "stage 1" | grep -v test | say_and_pass "stage 2"
所以从概念上讲,这会大声说“阶段 1”,然后立即说“阶段 2”,然后将 grepped 的内容转储/etc/password
到标准输出。
我最初对say_and_pass
脚本的破解是这样的:
say_and_pass
#!/usr/bin/env bash
OUT="$*"
say "$OUT" && cat
但这似乎不起作用;-)
编辑:我将上面的示例更改为say_and_pass "stage2"
用作最终命令,这是我的解决方案工作所必需的......
您在这里尝试做的问题是您似乎有两个数据流——一个
say
用于文本处理,一个用于文本处理(即cat
和grep
)。您不能为此使用单个管道,因为它只会混合数据。
cat /etc/passwd | say
将使您的计算机尝试说出文件的全部内容。此外,say
不会向标准输出写入任何内容,因此不会再往下流。如果您确实想“中断”您的数据处理流以处理对其他实用程序的单独输出,例如
say
,您需要为您的一个或另一个数据流设置一个 FIFO(即“命名管道”),或者使用写入磁盘的临时文件。您的演示用例对示例没有多大帮助,因为尽管有
say
s,但您只是在ping 一个文件,这可以通过(是无用的使用grep
)一步完成。grep -v test /etc/passwd
cat file | grep pattern
cat
综上所述,一个使用暂存文件的示例:
还有一个使用命名管道
say
:原来我所要做的就是在我的脚本开始时消耗所有的标准输入......我不希望它在收到标准输入时处理它,但是当管道链中的整个前一个命令完成时。
所以我的
say_and_pass
脚本就是这个,它适用于我的用例!尝试:
我的系统上实际上没有
say
,但这有效:H!
我建议,根据您自己的回答,将标准输入转储到标准输出,删除将其存储到变量的部分。这应该会减少内存消耗,并使管道链像管道一样工作(一条线,它被处理,并将结果发送到下一个进程)。
这个版本
say_and_pass
可以满足 OP 的要求:它使用一个临时文件,就像@DopeGhoti 建议的那样,但将任何其他逻辑(
grep
例如,)保留在脚本之外。这使得它say_and_pass
更加通用和可重用。我对目标/目的的解释是,我们需要一种可听的方式来监控可能较长的管道的进度。
所以运行时:
作为用户,您可以听得见
cmd1
已完全执行完毕;权衡是在完成cmd2
之前无法开始处理其标准输入cmd1
。但似乎 OP 意识到了这种权衡并愿意这样做。这类似于@BradParks 的答案,但不受 bash 可用内存的限制(正如@agc 指出的那样),并且在避免意外污染标准输出方面更加小心。
另请注意,无需将消息捕获到自己的变量中,因此我们也只需转发
"$@"
到say
.如果你使用&&,它的意思是,在执行第二个命令之后执行第一个命令,但第一个命令的结果对于第二个命令并不重要。我的意思是你有 2 个不同的命令,因为你使用 &&。如果你使用 |,它的意思是第一个命令做某事并为第二个命令提供一些东西。最后,您应该为 cat 命令提供一个属性。顺便说一句对不起我的英语