我试图弄清楚如何等待命令完成,然后将标准输入通过管道传输到标准输出。我使用的是 Mac,但我认为我的问题更多是关于如何等待进程完成并通过管道传输输出,然后是与 Mac 相关的任何事情。
我注意到,在 Mac 上,我可以say
一起运行几个命令,如果我使用运算符将它们连接起来,它们会等待每个短语完全说出后再开始下一个短语&&
。
$ say "stage 1" && say "stage 2"
Run Code Online (Sandbox Code Playgroud)
这就是真正的用例 - 我有一个 bash 脚本,我希望它在完成某些操作后将stdin 传递到 stdout。
$ cat /etc/passwd | say_and_pass "stage 1" | grep -v test | say_and_pass "stage 2"
Run Code Online (Sandbox Code Playgroud)
所以从概念上讲,这会大声说“阶段 1”,然后立即说“阶段 2”,然后将 grep 的内容转储/etc/password
到标准输出。
我对say_and_pass
脚本的初步破解是这样的:
#!/usr/bin/env bash
OUT="$*"
say "$OUT" && cat
Run Code Online (Sandbox Code Playgroud)
但它似乎不起作用;-)
编辑:我更改了上面的示例以用作say_and_pass "stage2"
最终命令,这是我的解决方案工作所必需的......
这个版本的功能say_and_pass
符合OP的要求:
#!/usr/bin/env bash
# Create a temporary file to store stdin
TEMP_STDIN="$(mktemp)"
# Capture stdin and save it to temporary file
cat - > "${TEMP_STDIN}"
# say message, but prevent any output to stdout
say "$@" > /dev/null
# Dump saved stdin to stdout
cat "${TEMP_STDIN}"
# Clean up, but prevent any output to stdout
rm -f "${TEMP_STDIN}" > /dev/null
Run Code Online (Sandbox Code Playgroud)
它使用一个临时文件,就像 @DopeGhoti 建议的那样,但将任何其他逻辑(例如grep
)保留在脚本之外。这使得它say_and_pass
更加通用和可重用。
我对目标/目的的解释是,我们需要一种可听的方式来监控可能很长的管道的进度。
所以运行时:
cmd1 | say_and_pass "stage 1" | cmd2 | say_and_pass "stage 2"
Run Code Online (Sandbox Code Playgroud)
作为用户,您可以通过声音知道已经cmd1
完全完成其执行;权衡是在完成cmd2
之前无法开始处理其标准输入。cmd1
但OP似乎意识到了这种权衡并愿意做出这种权衡。
这与 @BradParks 的答案类似,但不受 bash 可用内存的限制(正如 @agc 指出的那样),并且在避免意外污染 stdout 方面稍微更加小心。
另请注意,无需将消息捕获到其自己的变量中,因此我们也只需转发"$@"
到say
.