Por que este 'grep -v' não está funcionando como esperado?

12

Eu tenho um problema estranho relacionado a grep -v consultas. Permita-me explicar:

Para exibir conexões, uso who :

$ who
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

O atual tty do meu terminal é pts/0

$ tty
/dev/pts/0
$ tty | cut -f3-4 -d'/'
pts/0

Eu tento excluir minha própria conexão usando grep -v $(tty | cut -f3-4 -d'/') . A saída esperada desse comando deve ser who , sem minha conexão. No entanto, a saída é mais inesperada:

$ who | grep -v $(tty | cut -f3-4 -d'/')
grep: a: No such file or directory
grep: tty: No such file or directory

Coloco o $(...) entre aspas e parece corrigir o problema "Nenhum arquivo ou diretório". No entanto, minha conexão ainda é impressa, mesmo que meu tty ( pts/0 ) tenha sido excluído:

$ who | grep -v "$(tty | cut -f3-4 -d'/')"
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

A partir deste ponto, não tenho absolutamente nenhuma ideia do motivo pelo qual a consulta grep está com defeito.

    
por perhapsmaybeharry 08.12.2016 / 13:49

2 respostas

18

Zachary explicou a origem do problema.

Enquanto você pode contornar isso com

tty=$(tty)
tty_without_dev=${tty#/dev/}
who | grep -v "$tty_without_dev"

Isso seria errado, por exemplo, se esse tty for pts/1 , você acabaria excluindo todas as linhas contendo pts/10 . Algumas implementações grep têm uma opção -w para fazer uma pesquisa de palavras

who | grep -vw pts/1

não corresponderia a pts/10 porque o pts/1 não é seguido por um caractere que não seja de palavra.

Ou você pode usar awk para filtrar o valor exato do segundo campo, como:

who | awk -v "tty=$tty_without_dev" '$2 != tty'

Se você quiser fazer isso em um comando:

{ who | awk -v "tty=$(tty<&3)" '$2 != substr(tty,6)'; } 3<&0

O stdin original sendo duplicado no descritor de arquivo 3 e restaurado para o comando tty .

    
por 08.12.2016 / 15:09
20

A partir da página de informações do tty.

'tty' prints the file name of the terminal connected to its standard input. It prints 'not a tty' if standard input is not a terminal.

O problema é que no seu exemplo o stdin do tty é um pipe, não o seu terminal.

Você pode ver este exemplo.

$ tty
/dev/pts/29
$ echo | tty 
not a tty

Para contornar isso você poderia fazer algo assim.

who | grep -wv "$(ps ax | awk "\ == $$ {print \}" )"

Existe uma maneira mais rápida / mais eficiente, mas requer dois comandos.

t=$(tty)
who|grep -wv "${t:5}"
    
por 08.12.2016 / 14:39