grep 交互式程序

grep 交互式程序

我有一个类似 shell 的交互式程序,它会输出许多不相关的错误消息,让我们的客户感到困惑。每条错误消息都是以“%”开头的整行消息。

因此,摆脱它们的简单方法是这样的:

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

命令是类似 shell 的程序。

但问题是,它只在收到换行符后才向用户输出任何内容。因此,当用户在程序中输入任何内容时,在按下 Enter 键之前,不会有任何关于输入内容的反馈。

有没有办法做这样的非线基础的事情?我想过用 Python 编写一些东西,但是在那台机器(非常慢的嵌入式设备)上启动 Python 需要几秒钟,这是不可接受的。

为了更加清楚,我将解释更多:

该程序不受我的控制,因此我无法更改它的功能(否则我只会让程序停止输出这些错误消息)。该程序用于以 Cisco-Shell 方式查看或更改设备上的设置。典型的用户交互可能如下所示:

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#

每次用户按下某个键时,他们键入的字母都会在键入时出现在屏幕上,以便他们可以看到自己键入的内容,类似于在常规 bash shell 上。

现在如果我做这样的事情:

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

然后,输入的字母(以及输入提示)只会在用户按下 Enter 键并结束该行后才会显示,因为 grep 会缓存行。所以像这样(“<”=来自用户的输入,“>”来自程序的输出):

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

现在看起来像这样:

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

正如您所看到的,当程序发送它时,它不会单独输出每个字符,而是等待下一个 \n,然后 grep 转发内容。

我不确定 grep 实际上可以做我想做的事,所以我也愿意接受对其他程序的建议。

答案1

grep定义的匹配、保留或丢弃行,因此必须在匹配之前读取整行;那无法实现你想要的。

首先,您需要验证是否command将输入字符一一回显到管道。当 stdout 是实现定义的“交互式设备”时,标准 C 程序(有时还有其他使用 C stdio 的程序)默认使用行缓冲,否则使用全缓冲,并且管道通常不定义为交互式。您command已经在 tty 上表现异常,但检查它在带有 的管道上是否仍然如此command | dd bs=1

如果这不起作用,您将需要一个为 建立伪 tty (pty) 的程序,例如Mark Plotnick 建议的command精简程序。script

如果回显管道确实可以在侧面工作command,那么您所需要的只是管道右侧的一些东西,而无需等待整行。一个简单的 C 程序就可以做到这一点,例如:

#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');
  }
}

或者,如果您有bash(IMLE 嵌入式设备往往不会)尝试包含以下内容的脚本

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

答案2

行首用 完成^,行尾用 完成$\n无法识别字符。并且行尾永远不会匹配(默认情况下)。

所以你应该使用类似的东西 grep -v "^%.*$"

答案3

sed有一个无缓冲模式,所以以下应该也可以工作:

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

相关内容