仅获取终端解释字符串的可见输出

仅获取终端解释字符串的可见输出

我正在开发一个脚本,通过创建一个显示任何包含空格以外的任何列的掩码,可以轻松找到哪些列是“仅空格”。

为此:我将每一行打印为“相互重叠”+将空格修改为“右箭头”。 (另一个步骤是忽略“比最后一个标题开头更远的列”之后看到的空格,但这不是这里的主题)

我在最后一步中遇到了麻烦:如何获取结果字符串(我的终端正确显示的输出),而不<Esc>[C使用用于创建/解释它的每个 \r、\n 和 (= 右箭头)。

示例:

$ PS2=""
$ Esc=$( printf '\033' )
$ Right=$( printf "${Esc}[C" )
$ ps | head -n 2
  PID TTY          TIME CMD
12415 pts/1160 00:00:00 bash
$ ps | head -n 2 | LC_ALL=C tr '!-~' '*'
  *** ***          **** ***
***** ******** ******** ****
$ ps | head -n 2 | LC_ALL=C tr '!-~' '*' | sed -e "s/ /${Right}/g" | while read line; do
    printf "%s\r" "$line"
  done ; printf '\n'
***** ******** ******** ****
  ## the line above is what I am looking for: 
  ## a "mask" of each column that at one point had a non-space character displayed in it
$ ( ps | head -n 2 | tr '!-~' '*' | sed -e "s/ /${Right}/g" | while read line; do
      printf "%s\r" "$line"
    done ; printf '\n'
  ) | cat -ve
^[[C^[[C***^[[C***^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[C****^[[C***^M*****^[[C********^[[C********^[[C****^M$
  ## but of course, the terminal sees (and outputs) this instead, which contains all the "contructing characters"

我如何在变量中检索字符串“如我的终端所示”,即:

***** ******** ******** ****

(我尝试将整个内容输出到“ while read -e Finalstring; do print '[%s]' "$finalstring" ; did ,但是该 FinalString 仍然包含整个“预解释”字符串,而不是“终端后解释”)

询问同一问题的简短方法:

# if:
$ printf "aaaa\rbb\rc\n"
# displays:
cbaa
$ var=$( printf "aaaa\rbb\rc\n" ) # $var will be: "aaaa\rbb\rc\n"
# how can I instead have the resulting "displayed string": "cbaa" in $var ?

答案1

看来您只是通过向本来就没有终端转义的数据添加终端转义来制造额外的问题。如果您想要的只是可视化 中的空白列ps,您可以使用awk(看起来您知道)来简单地累积按列号索引的数组,该数组全是空白,并在必要时获取“*”。例如:

awk '
{ len = length($0)
  if(len>max)max = len
  for(i=1;i<=len;i++) if(substr($0,i,1)!=" ") col[i] = "*"
}
END{ for(i=1;i<=max;i++) if(col[i])str = str "*"; else str = str " ";
     print str
}'

答案2

我多年前使用过的一个简单的 ansi 解析器是 Python 模块提供的解析器期待。 (遗憾的是,现在已弃用此功能pyte,取而代之的是我不熟悉的模块。)

这个旧模块似乎仍然作为包的一部分提供。您向它发送一个数据流,它会将字符写入 40x80 数组中的适当位置,同时考虑到 ansi 转义序列。

以下示例挂钩向上滚动操作,并保留一个result包含 80 个字符的单行数组,并在非空格字符向上滚动出屏幕的位置放置一个“*”。屏幕上的调用str()改为向上滚动整个屏幕以刷新它,然后只返回这个数组。只需将您的数据输入该程序即可。这只是一个开始,因为您可能还想在空格覆盖非空格字符时禁止更新数组,等等。

#!/usr/bin/python3
# https://unix.stackexchange.com/q/711733/119298
# extend ANSI by noting which cols get non-whitespace
import sys, re
from pexpect.ANSI import ANSI

class KeepScroll(ANSI):
    def __init__(self, r=24,c=80):
        ANSI.__init__(self,r,c)
        ANSI.Log = None
        self.result = [" "] * self.cols

    def scroll_up(self):
        if self.scroll_row_start==1:
            for i, ch in enumerate(self.w[0]):
                if ch!=" ": self.result[i] = "*"
        ANSI.scroll_up(self)

    # scroll up rest of screen
    def __str__(self):
        for i in range(self.rows): self.scroll_up()
        return "".join(self.result)

def parsevt100(data):
    scr = KeepScroll()
    scr.write(data)
    return str(scr)

if __name__ == "__main__":
    print(parsevt100(sys.stdin.read()))

相关内容