추가 댓글

추가 댓글

script -c나는 진행 상황을 모니터링하고 결과를 이메일로 보낼 수 있도록 명령을 실행하고 출력을 로그 파일에 기록하여 일석이조를 시도하는 bash 스크립트를 가지고 있습니다 .

최종 로그 파일은 모든 진행 상황 출력이 기록되는 터미널 세션에 표시되는 모든 항목의 타이프스크립트이기 때문에 상당히 깁니다. 그러나 read data 를 사용하면 cat터미널에 최종 출력만 표시됩니다.

예를 들어: script -c 'rsync -ah --info=progress2 folder1 folder2' logfile.log

다음 명령을 사용하여 파일을 엽니다 nano.

> # nano logfile.log
Script started on 2021-07-20 14:22:40+0800
^M         36.84M   0%   34.31GB/s    0:00:00 (xfr#1, to-chk=606/673)^M        808.26M   7%  752.75GB/s    0:00:00 (xfr#31, to-chk=603/673)^M        860.63M   7%  801.52GB/s    0:00:00 (xfr#34, to-chk=592/673)$

Script done on 2021-07-20 14:22:40+0800

반면,cat

> # cat logfile.log                                                                                                                                                                                              
Script started on 2021-07-20 14:22:40+0800
         11.48G 100% 10693.06GB/s    0:00:00 (xfr#616, to-chk=0/673)

Script done on 2021-07-20 14:22:40+0800

그러나 cat출력이 파일에 기록되는 경우:

> # cat logfile.log > temp.log

결과에는 temp.log전체 원시 데이터가 포함됩니다.


  1. 차이점이 있는 이유는 무엇입니까?

  2. cat디스플레이의 원시 출력이 아닌 디스플레이에서 얻은 것과 동일한 출력을 이메일로 보내고 싶습니다 nano. 그러나 cat원시 데이터는 항상 파일, 다른 명령 등으로 출력됩니다.

아래 명령은 이메일을 통해 원시 데이터를 보냅니다.

> # echo -e "Subject : report" "\n\n\n `cat logfile.log`" | sendmail [email protected]
  1. TypeScript 파일에서 모든 원시 데이터를 지울 수 있는 방법이 있습니까? 온라인이나 매뉴얼에서 아무것도 찾지 못했습니다.

추가 댓글

조언과 설명 감사드립니다. 실제로 주석에서 제안한 대로 및 를 사용하여 출력을 정리할 수 있었습니다
.rsynctrsed

그러나 프로그램 없이 명령을 실행하거나 -v다른 프로그램(예를 들어)을 실행 하면 restic로그에 많은 삭제 시퀀스가 ​​표시됩니다.

^[[2K[13:34] 487210 files 165.864 GiB, total 503917 files 230.290 GiB, 0 errors

^[[2K[13:34] 487218 files 165.972 GiB, total 503960 files 230.477 GiB, 0 errors

^[[2KFiles:         176 new,     3 changed, 633544 unmodified

^[[2K

^[[2KDirs:          260 new,   140 changed, 106144 unmodified

^[[2K

^[[2KAdded to the repo: 363.231 MiB

^[[2K

^[[2K

^[[2K

^[[2Kprocessed 633723 files, 535.105 GiB in 14:34

^[[2K

^[[2Ksnapshot 9394ca81 saved

^[[2K

^[[2K

^[[1A
Script done on 2021-07-20 00:06:12+0800

가 있는 항목을 제거할 수 있습니다 sed.

cat터미널의 마지막 출력을 파일에 직접 쓰거나 파이프하는 방법이 있다면 더 깨끗하고 일반적인 솔루션이 될 수 있습니까 sponge?

답변1

좋아요, 여기에 이 ​​정리를 시도하는 (상대적으로) 간단한 Python 스크립트가 있습니다. 나는 그것을 부른다 clean-typescript.py. 확실히 개선될 수 있고 버그가 있을 수 있지만 이것이 제가 짧은 시간 안에 생각해 낼 수 있는 것입니다.

#!/usr/bin/env python3
# Takes raw terminal output of a program containing control sequences that
# overwrite parts of the output, and attempts to transform it to just the end
# result, writing its output on stdout.
#
# Assumptions/limitations:
#  * Assumes Unix line endings.
#  * Assumes input text is left-to-right, in system character encoding.
#  * Does not attempt to deal with most of the complexities of Unicode.
#  * Does not attempt to interpret every ANSI escape sequence; just the common
#    ones that affect cursor position.
#  * Ignores ANSI SGR (bold/color/etc.) sequences.
#  * Assumes 8-column tab stops.
#  * Assumes the terminal displays an unlimited number of lines.
#  * Ignores absolute positioning sequences (except CHA): this is not for
#    ncurses output and such.
#  * Will not allow the cursor to go up beyond the first line in the file.
#
# Usage: clean-typescript.py FILE COLS
# FILE is the name of the file to read; if omitted or "-", read stdin.
# COLS is how many columns wide the terminal is; if omitted, set to 80.

import sys
from array import array
from enum import Enum

if len(sys.argv) >= 2 and sys.argv[1] != "-":
    f = open(sys.argv[1], "r")
else:
    f = sys.stdin

if len(sys.argv) >= 3:
    cols = int(sys.argv[2])
else:
    cols = 80

lines = [array("u", (" ",)*cols)]
curline = curcol = 0
eol = False

class Dir (Enum):
    UP = 0
    DOWN = 1
    RIGHT = 2
    LEFT = 3

def move_cursor (dir: Dir, count: int):
    global curline, curcol, eol
    if dir == Dir.UP:
        pos = curline - count
        curline = pos if pos >= 0 else 0
    elif dir == Dir.DOWN:
        pos = curline + count
        curline = pos if pos < len(lines) else len(lines) - 1
    elif dir == Dir.RIGHT:
        pos = curcol + count
        curcol = pos if pos < cols else cols - 1
    elif dir == Dir.LEFT:
        eol = False
        pos = curcol - count
        curcol = pos if pos >= 0 else 0

def skip_osc ():
    c = f.read(1)
    while True:
        if c == "\x07":
            return f.read(1)
        if c == "\x1b":
            if f.read(1) == "\\":
                return f.read(1)
        c = f.read(1)

def interpret_seq ():
    c = f.read(1)
    if c == "]": # OSC
        return skip_osc()
    if c != "[": # CSI
        # Other Fe seqs. not supported
        return f.read(1)

    parms = []
    c = f.read(1)
    while True:
        p = ""
        while c >= "0" and c <= "9":
            p += c
            c = f.read(1)
        if p:
            parms.append(int(p))

        if c != ";": break
        c = f.read(1)

    if c == "A":   # CUU
        move_cursor(Dir.UP, parms[0] if len(parms) > 0 else 1)
    elif c == "B": # CUD
        move_cursor(Dir.DOWN, parms[0] if len(parms) > 0 else 1)
    elif c == "C": # CUF
        move_cursor(Dir.RIGHT, parms[0] if len(parms) > 0 else 1)
    elif c == "D": # CUB
        move_cursor(Dir.LEFT, parms[0] if len(parms) > 0 else 1)
    elif c == "E": # CNL
        move_cursor(Dir.LEFT, cols)
        move_cursor(Dir.DOWN, parms[0] if len(parms) > 0 else 1)
    elif c == "F": # CPL
        move_cursor(Dir.LEFT, cols)
        move_cursor(Dir.UP, parms[0] if len(parms) > 0 else 1)
    elif c == "G": # CHA
        move_cursor(Dir.LEFT, cols)
        move_cursor(Dir.RIGHT, parms[0] - 1 if len(parms) > 0 else 0)
    # CUP and ED not implemented
    elif c == "K": # EL
        if (len(parms) == 0 or parms[0] == 0) and not eol:
            for i in range(curcol, cols):
                lines[curline][i] = " "
        elif parms[0] == 1:
            for i in range(0, curcol):
                lines[curline][i] = " "
            if eol:
                append_line()
                move_cursor(Dir.LEFT, cols)
                move_cursor(Dir.DOWN, 1)
        elif parms[0] == 2:
            for i in range(0, cols):
                lines[curline][i] = " "
            if eol:
                append_line()
                move_cursor(Dir.LEFT, cols)
                move_cursor(Dir.DOWN, 1)
    # ED, SU, SD, and HVP also not implemented

    c = f.read(1)
    return c

def append_line ():
    lines.append(array("u", (" ",)*cols))

c = f.read(1)
while c:
    if c == "\x08":   # BS
        if eol:
            eol = False
        else:
            move_cursor(Dir.LEFT, 1)
    elif c == "\x09": # HT
        curcol = (curcol + 8)//8*8
        if curcol >= cols: curcol = cols - 1
    elif c == "\x0a": # LF (implies CR in Unix)
        eol = False
        if curline == len(lines) - 1: append_line()
        move_cursor(Dir.LEFT, cols)
        move_cursor(Dir.DOWN, 1)
    elif c == "\x0b" or c == "\x0c": # VT/FF: just go down one line
        if curline == len(lines) - 1: append_line()
        move_cursor(Dir.DOWN, 1)
    elif c == "\x0d": # CR (stays on same line)
        eol = False
        move_cursor(Dir.LEFT, cols)
    elif c == "\x1b": # Escape seq.
        c = interpret_seq()
        continue
    elif (c >= "\x20" and c <= "\x7e") or c >= "\xa1":
        if not eol: lines[curline][curcol] = c
        if curcol == cols - 1:
            if eol:
                if curline == len(lines) - 1: append_line()
                move_cursor(Dir.LEFT, cols)
                move_cursor(Dir.DOWN, 1)
                lines[curline][curcol] = c
                move_cursor(Dir.RIGHT, 1)
            else:
                eol = True
        else:
            move_cursor(Dir.RIGHT, 1)

    c = f.read(1)

# Final result
print(*("".join(line).rstrip() for line in lines), sep="\n", end="")

관련 정보