Por que o grep não remove linhas de saída de terminal do comando find por padrão? [duplicado]

0

Estou constantemente frustrado com esse comando simples:

find / | fgrep somestuff.ext

Quando não uso sudo , recebo linha após linha de permissão negada - o que é justo, mas por que essa saída não é ignorada quando o grep a lê do pipe?

Por que essa forma de saída é enviada diretamente para a janela do terminal e não passada para o pipe (o que eu suspeito que esteja acontecendo) e subsequentemente ignorada pelo grep, enquanto as mesmas linhas são produzidas pelo cat? em um arquivo de texto) iria corretamente para o pipe e seria ignorado pelo meu padrão grep?

Eu sinto que há algo sobre o processo STDIN / STDOUT que não estou entendendo aqui

    
por MJHd 26.11.2018 / 23:44

2 respostas

0

Enquanto a boa resposta da choroba cura o seu problema, a razão para o comportamento que você notou é o comportamento padrão do pipeline no bash (e eu suponho na maioria dos shells também).

Conforme descrito na seção man bash pipelines:

The standard output of command is connected via a pipe to the standard input of command2. This connection is performed before any redirections specified by the command (see REDIRECTION below).

Isso significa que stderr de command1 não é alimentado por padrão para command2 através do pipe, mas é direcionado para seu tty, o link stderr padrão.

O manual do Bash também diz:

If |& is used, command's standard error, in addition to its standard output, is connected to command2's standard input through the pipe; it is shorthand for 2>&1 |.

Portanto, no seu caso, se você deseja canalizar para o comando grep, os erros do comando de localização, que por padrão são enviados para /dev/stderr , você precisa usar um destes dois formulários:

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

Sua queston também pode ser chamada "Por que o stderr é ignorado por pipes".

E a resposta é porque é assim que o bash e o linux são feitos por padrão; tratar stdout diferentemente de stderr , para que o usuário seja capaz de registrar / tratar essas duas saídas de maneira diferente.
Por exemplo, você pode canalizar stdout do comando1 para stdin do comando2 e, ao mesmo tempo, pode enviar stderr do comando1 para um arquivo de log usando 2>errorlog.txt .

Na verdade, quando você executa um comando sem nenhum redirecionamento especificado como

find /

É equivalente a

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

Qual é finalmente resolvido para:

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

como pode ser verificado por um único 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

Se, por algum motivo, você quiser "associar" stdout e stderr de um comando, será necessário declarar explicitamente suas finalidades como bash usando |& (para pipelines) ou 2>&1 (para qualquer tipo de redirecionamento de saída)

    
por 28.11.2018 / 01:48
7

As mensagens de permissão negada não são enviadas para stdout de find , mas para stderr. Você pode redirecionar o stderr inteiro para o intervalo de bits:

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

Além disso, para encontrar o arquivo fornecido, você não precisa de nenhum grep:

find . -name somestuff.ext

para o qual você ainda pode aplicar o 2>/dev/null .

Para suprimir apenas as mensagens de permissão negada, você pode usar

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

no bash.

    
por 26.11.2018 / 23:47