我正在编写一个脚本,该脚本将运行一个输出到 STDOUT 的校验和进程,然后我想 grep 查找匹配 OK 或 FAILED 的行,并对这些匹配执行不同的操作(即输出到终端和日志)。我观看了大量的 Youtube 视频并阅读了大量有关重定向的内容,但我似乎无法理解重定向到底是如何工作的。我想做的是将 STDOUT 链接到多个 grep,而不让它们吞噬不匹配的文本。
这是我尝试使用 cat 而不是 md5sum 的概念,每行都有一个动物名称的文本文件(DOG、CAT、PONY、RHINO、DEER、FOX):
{ cat test.txt 3>&1 | tee /dev/fd/3 | grep DOG; } 3> results.txt
这符合我的预期。我在这里理解的是,我正在对文件执行 cat 操作,然后打开 fd3,它指向写入 STDOUT(fd1) 的内容。由于 grep 会吞噬 fd1 中的所有内容,因此我将 cat 的 STDOUT 显式发送到 fd3,然后通过管道将 STDOUT 传输到 grep。 Grep 将打印出与 DOG 匹配的行,然后从 cat 写入 fd3 的所有文本将被推送到 results.txt 文件。
现在,要链接另一个 grep 来查找其他文本,我必须将 fd3 数据指向 STDOUT,将其显式返回到 fd3,然后将 STDOUT 通过管道传输到新的 grep。
{ { cat test.txt 3>&1 | tee /dev/fd/3 | grep DOG; } 3>&1 | tee /dev/fd/3 | grep PONY; } 3> results.txt
这里的第一个问题是来自第一个 grep 的 STDOUT 被第二次推入 fd3,而不是打印到终端。所以现在我的 results.txt 变得重复,并且我从未在第一个 grep 中将任何内容打印到屏幕上。这就是我对重定向的理解崩溃的地方。我有点明白发生了什么,但我无法找到一个简单的解决方案。
我想 grep STDOUT,将结果打印到屏幕上,并将原始文本传递给另一个 grep,也许是第三个、第四个等,而不修改我传递给每个 GREP 的原始文本,并且每个后续的 grep 都不会吃掉上一个'匹配应该打印到屏幕上。
我可能可以通过存储一个变量并在多行 grep 上调用它来做到这一点,但随后我必须等待整个第一个命令完成。就我正在开发的应用程序而言,我希望在校验和期间看到实时结果,而不仅仅是一个小时的空白屏幕,直到整个过程完成。任何关于我做错了什么的澄清都会非常有帮助,谢谢!
编辑
我知道 cat 的确切用法是没有意义的,我只是用它来演示这个概念。在我将应用这个概念的脚本中,第一个命令实际上是:
md5sum -c checksum.md5
它将读取校验和文件,重新哈希源并将通过/失败行输出到 STDOUT。然后我想 grep 这个流并将结果发送到单独的日志和/或终端输出 - 但 cat 似乎是演示问题的更简单方法,因为这可以应用于过滤任何命令和 grep 流,例如 find、md5 、ls 等
答案1
您可以通过流程替换更好地完成您所要求的事情:
尽可能接近您原来的命令:
cat test.txt | tee >(grep DOG) >(grep PONY) >results.txt
删除 cat 的无用使用:
<test.txt tee >(grep DOG) >(grep PONY) >results.txt
或者:
tee >(grep DOG) >(grep PONY) <test.txt >results.txt
答案2
isaac 的解决方案更好,但你的方法如下所示:
{ <input tee results.txt /dev/fd/3 | grep DOG >&2; } 3>&1 |
{ tee /dev/fd/3 | grep PONY >&2; } 3>/dev/null
或三个
{ <input tee results.txt /dev/fd/3 | grep DOG >&2; } 3>&1 |
{ tee /dev/fd/3 | grep PONY >&2; } 3>&1 |
{ tee /dev/fd/3 | grep CAT >&2; } 3>/dev/null