Bash

grepping 的重定向和管道

  • January 14, 2018

我正在編寫一個腳本,該腳本將執行一個校驗和過程,該過程輸出到 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

這符合我的預期。我在這裡的理解是我在文件上做一個貓,然後打開 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 似乎是一種更簡單的方法來展示問題,因為這可以應用於過濾任何命令和 grepping 流,例如 find、md5 , ls 等

您可以通過流程替換更好地滿足您的要求:

  1. 盡可能接近您的原始命令:
cat test.txt | tee >(grep DOG) >(grep PONY) >results.txt
  1. 去掉 cat 的無用用法:
<test.txt tee >(grep DOG) >(grep PONY) >results.txt

或者:

tee >(grep DOG) >(grep PONY) <test.txt >results.txt

艾薩克的解決方案更好,但你的方式看起來像這樣:

{ <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

引用自:https://unix.stackexchange.com/questions/416918