為什麼 grep 預設不從 find 命令中刪除終端輸出行?
我經常對這個簡單的命令感到沮喪:
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)。
這意味著預設情況下,
stderr
ofcommand1
不是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 通過管道傳輸到stdin
command2,同時您可以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
如果出於任何原因您想“加入”一個命令
stdout
,stderr
那麼您需要明確聲明您bash
使用|&
(用於管道)或2>&1
(用於任何類型的輸出重定向)的目的