문자열을 해석하는 터미널의 가시적 출력만 가져옵니다.

문자열을 해석하는 터미널의 가시적 출력만 가져옵니다.

공백 이외의 항목이 포함된 열을 표시하는 마스크를 만들어 "공백만"인 열을 쉽게 찾을 수 있는 스크립트를 작성 중입니다.

이렇게 하려면 각 줄을 "서로 겹치는" 것으로 인쇄하고 공백을 "오른쪽 화살표"로 수정했습니다. (또 다른 단계는 "마지막 헤더의 시작 부분보다 더 먼 열" 뒤에 표시되는 공백을 무시하는 것입니다. 그러나 여기서는 이것이 주제가 아닙니다.)

<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익숙하지 않은 모듈로 대체되었습니다.)

이 오래된 모듈은 여전히 ​​패키지의 일부로 사용 가능한 것 같습니다. 데이터 스트림을 보내면 ansi 이스케이프 시퀀스를 고려하여 40x80 배열의 적절한 위치에 문자를 씁니다.

다음 예제에서는 위로 스크롤 작업을 연결하고 result80자의 한 줄 배열을 유지하며 공백이 아닌 문자가 화면에서 위로 스크롤될 때마다 "*"를 배치합니다. 대신 화면 호출은 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()))

관련 정보