grep no programa interativo

1

Eu tenho um programa tipo shell interativo, que gera muitas mensagens de erro irrelevantes, que confundem nossos clientes. Cada uma dessas mensagens de erro são mensagens de linha completa começando com "%".

Assim, a maneira fácil de se livrar deles seria algo assim:

command | grep -v "^%[^\n]*$"

Com o comando sendo o programa semelhante a shell.

Mas o problema é que isso só gera alguma saída para o usuário, depois de receber uma nova linha. Então, quando o usuário digita alguma coisa no programa, não há feedback do que eles digitaram, até que eles pressionem enter.

Existe uma maneira de fazer algo como isso não é baseado em linha? Pensei em programar um pouco algo em Python, mas nessa máquina (dispositivo embutido muito lento) iniciar o Python leva vários segundos, o que não é aceitável.

Para adicionar mais clareza, explicarei um pouco mais:

O programa que está em causa não está sob meu controle, então eu não posso mudar o que ele faz (senão eu acabei de fazer o programa parar de enviar essas mensagens de erro). O programa é usado para exibir ou alterar configurações no dispositivo em um estilo do Cisco-Shell. Uma interação típica do usuário pode se parecer com isso:

linux-shell# command
% Error: some meaningless error
fake-cisco-shell# show status
Status report: status ok
% Error: some meaningless error
fake-cisco-shell# exit
linux-shell#

Toda vez que o usuário pressiona uma tecla, a letra digitada aparece na tela à medida que ela é digitada, para que possam ver o que digitaram, semelhante a um shell comum.

Agora, se eu fizer algo assim:

command | grep -v "%[^\n]*\n"

Em seguida, as letras digitadas (e também o prompt de entrada) só aparecerão depois que o usuário pressionar enter e assim terminar a linha, porque o grep armazena as linhas. Então, algo assim ("<" = entradas do usuário, ">" saídas do programa):

> fake-cisco-shell# 
< s
> s
< h
> h
< o
> o
< w
> w
< \n
> \n
> Result of the command\n
> fake-cisco-shell#

Agora está assim:

>(no output)
< s
< h
< o
< w
< \n
> fake-cisco-shell# show\n
> Result of the command\n

Então, como você vê, ele não exibe cada caractere quando o programa o envia, mas, em vez disso, espera pelo próximo \ n e só então o grep encaminha o conteúdo.

Não tenho certeza se o grep pode realmente fazer o que eu quero, por isso também estou aberto a sugestões para outros programas.

    
por Dakkaron 15.06.2016 / 13:01

3 respostas

3

grep é definido para combinar e reter ou descartar as linhas, portanto, ele precisa ler a linha inteira antes de fazer a correspondência; que não consegue realizar o que você quer.

Primeiro, você precisa verificar se command faz esse eco de caracteres de entrada um por um para um canal. Programas padrão C (e às vezes outros programas usando C stdio) por padrão usam buffer de linha quando stdout é um 'dispositivo interativo' como definido pela implementação, mas o buffer total de outra forma, e pipe geralmente não é definido como interativo. Seu command já está se comportando de forma incomum em um tty, mas verifique se ele ainda faz isso em um canal com command | dd bs=1 .

Se isso não funcionar, você precisará de um programa que configure uma pseudo-tty (pty) para command , como o script sugerido por Mark Plotnick.

Se o eco no pipe funcionar no lado command , tudo o que você precisa é algo do lado direito do tubo que não espere por uma linha completa. Um programa C simples pode fazer isso, algo como:

#include <stdio.h>
int main (void) {
  setvbuf (stdout, NULL, _IONBF, 0);
  int c;
  while( (c = getchar()) != EOF ){
    int sel = c != '%';
    for( ; c != '\n' && c != EOF; c = getchar() ) 
      if( sel ) putchar (c);
    if( sel ) putchar ('\n');
  }
}

Ou se você tiver bash - que os dispositivos incorporados IMLE tendem a NÃO - tente um script que contenha

IFS=$'\n'
while read -rn1 c; do y=true; [[ "$c" == "%" ]] && y=false;
  while ! [[ "$c" == "" ]]; do $y && printf "%c" "$c"; read -rn1 c || exit; done
  $y && printf "\n"; done
    
por 15.06.2016 / 22:04
0

O início da linha é feito com ^ e fim de linha com $ . Os caracteres \n não são reconhecidos. E o fim da linha nunca é correspondido (por padrão).

Então você deve usar algo como grep -v "^%.*$" .

    
por 15.06.2016 / 16:10
0

sed tem um modo sem buffer, portanto, o seguinte também deve funcionar:

… | sed -u -r '/%[^\n]*\n/d'

    
por 16.06.2016 / 11:59