Bash

為什麼 grep 預設不從 find 命令中刪除終端輸出行?

  • November 28, 2018

我經常對這個簡單的命令感到沮喪:

find / | fgrep somestuff.ext

當我不使用sudo時,我得到一行又一行的權限被拒絕 - 這很公平,但是當 grep 從管道讀取它時,為什麼不忽略這個輸出?

為什麼這種形式的輸出直接發送到終端視窗而不是傳遞到管道中(我懷疑一定會發生這種情況)並隨後被 grep 忽略,而由 cat 產生的相同行(比如我有權限被拒絕消息儲存在文本中文件)會正確進入管道並被我的 grep 模式忽略嗎?

我覺得這裡有一些關於 STDIN/STDOUT 過程的東西我不理解

權限被拒絕消息不會從 stderr 發送到 stdout,find而是發送到 stderr。您可以將整個 stderr 重定向到位桶:

find 2>/dev/null | fgrep somestuff.ext

此外,要查找給定的文件,您不需要任何 grepping:

find . -name somestuff.ext

您仍然可以對其應用2>/dev/null.

要僅抑制權限被拒絕的消息,您可以使用

2> >(grep -v 'Permission denied' >&2)

在重擊中。

雖然 choroba 的好答案解決了您的問題,但您注意到的行為的原因是 bash 中的預設管道行為(我想在大多數 shell 中也是如此)。

man bash管道部分所述:

command 的標準輸出通過管道連接到 command2 的標準輸入。此連接在命令指定的任何重定向之前執行(請參閱下面的 REDIRECTION)。

這意味著預設情況下, stderrofcommand1不是command2通過管道輸入的,而是被驅動到您的 tty,即預設的 stderr 連結。

Bash手冊還說:

如果使用|&,command 的標準錯誤,除了它的標準輸出,通過管道連接到command2 的標準輸入;它是 2>&1 | 的簡寫。

因此,在您的情況下,如果您想通過管道傳輸到 grep 命令,則預設發送給/dev/stderr您的 find 命令錯誤需要使用以下兩種形式之一:

find / |& fgrep somestuff.ext
find / 2>&1 | fgrep somestuff.ext

您的問題也可以標題為“為什麼管道忽略標準錯誤”。

答案是因為這就是 bash 和 linux 預設的製作方式;stdout區別對待stderr,以便使用者能夠以不同方式記錄/處理這兩個輸出。

例如,您可以stdout將 command1 通過管道傳輸到stdincommand2,同時您可以stderr使用 .將 command1 發送到日誌文件2>errorlog.txt

實際上,當您執行沒有指定任何重定向的命令時

find /

相當於

find / 1>/dev/stdout 2>/dev/stderr

最終解決為:

find / 1>/dev/tty1 2>/dev/tty1 #assuming that you are logged in tty1

正如可以通過一個單一的驗證ls

ls -all /dev/st*
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdout -> /proc/self/fd/1

ls -all /proc/self/fd/2
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/2 -> /dev/tty1

ls -all /proc/self/fd/1
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/1 -> /dev/tty1

如果出於任何原因您想“加入”一個命令stdoutstderr那麼您需要明確聲明您bash使用|&(用於管道)或2>&1(用於任何類型的輸出重定向)的目的

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