将sdout记录到文件中时实时处理退格控制字符^ H

问题描述

我正在研究一个脚本,以在后台测试新硬盘(以便我可以关闭终端窗口)并记录输出。我的问题是要让badblocks将stdout打印到日志文件,以便我可以监视其多日进度并创建格式正确的更新电子邮件。

我已经能够使用以下命令将stdout打印到日志文件:(标记为r / w,%monitor,详细)
sudo badblocks -b 4096 -wsv /dev/sdx 2>&1 | tee sdx.log

通常输出如下:
Testing with pattern 0xaa: 2.23% done,7:00 elapsed. (0/0/0 errors)

不使用换行符,^ H控制命令将备份光标,然后新的更新状态将覆盖以前的状态。

不幸的是,控制字符未处理,而是另存为文件中的字符,产生了上述输出,随后是^H的43个副本,新更新的统计信息,^H的43个副本等

由于输出至少每秒更新一次,因此生成的文件比必要的要大得多,并且使检索当前状态变得困难。

在终端中工作时,解决方案cat sdx.log && echo""通过解析控制字符(然后插入回车符,以便不被下一个终端行立即打印出来)来打印预期/期望的结果,但使用{ {1}}或cat sdx.log > some.file都仍包含所有多余的字符(尽管在电子邮件中它们被解释为空格)。这种解决方案(或类似的解决方案在访问时会解码或删除控制字符)仍然会产生巨大的不必要的输出文件。

我已经通过以下类似的问题进行了工作,但是没有一个(至少我可以弄清楚)产生一种解决方案,该解决方案可以与输出实时地更新文件,而不是要求保存的日志文件是在任务完成写入后单独处理,或者直到该过程完成后才写入日志文件,这两者都违反了监视进度的既定目标。

Bash - process backspace control character when redirecting output to file

How to "apply" backspace characters within a text file (ideally in vim)

谢谢!

解决方法

我在现实生活中遇到的主要问题是尝试处理手册页。过去,我一直使用一个简单的脚本,通过适当地去除退格键来发布进程。也许可以用80个字符的perl来做这种事情,但这是一种很好地处理backspace和cr / nl的方法。我没有进行广泛的测试,但是对于简单的情况,它会产生良好的输出。例如:

$ printf 'xxx\rabclx\bo\rhel\nworld\n' | ./a.out output
hello
world
$ cat output
hello
world
$ xxd output
00000000: 6865 6c6c 6f0a 776f 726c 640a            hello.world.

如果您的输出开始有很多csi序列,那么这种方法就是不值得的麻烦。在这些情况下,cat会产生很好的人工耗材输出。

#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

FILE * xfopen(const char *path,const char *mode);
off_t xftello(FILE *stream,const char *name);
void xfseeko(FILE *stream,off_t offset,int whence,const char *name);

int
main(int argc,char **argv)
{
        const char *mode = "w";
        char *name = strchr(argv[0],'/');
        off_t last = 0,max = 0,curr = 0;
        name = name ? name + 1 : argv[0];
        if( argc > 1 && ! strcmp(argv[1],"-a")) {
                argv += 1;
                argc -= 1;
                mode = "a";
        }
        if( argc > 1 && ! strcmp(argv[1],"-h")) {
                printf("usage: %s [-a] [-h] file [ file ...]\n",name);
                return EXIT_SUCCESS;
        }
        if( argc < 2 ) {
                fprintf(stderr,"Missing output file.  -h for usage\n");
                return EXIT_FAILURE;
        }
        assert( argc > 1 );
        argc -= 1;
        argv += 1;

        FILE *ofp[argc];
        for( int i = 0; i < argc; i++ ) {
                ofp[i] = xfopen(argv[i],mode);
        }
        int c;
        while( ( c = fgetc(stdin) ) != EOF ) {
                fputc(c,stdout);
                for( int i = 0; i < argc; i++ ) {
                        if( c == '\b' ) {
                                xfseeko(ofp[i],-1,SEEK_CUR,argv[i]);
                        } else if( isprint(c) ) {
                                fputc(c,ofp[i]);
                        } else if( c == '\n' ) {
                                xfseeko(ofp[i],max,SEEK_SET,argv[i]);
                                fputc(c,ofp[i]);
                                last = curr + 1;
                        } else if( c == '\r' ) {
                                xfseeko(ofp[i],last,argv[i]);
                        }
                }
                curr = xftello(ofp[0],argv[0]);
                if( curr > max ) {
                        max = curr;
                }
        }
        return 0;
}

off_t
xftello(FILE *stream,const char *name)
{
        off_t r = ftello(stream);
        if( r == -1 ) {
                perror(name);
                exit(EXIT_FAILURE);
        }
        return r;
}

void
xfseeko(FILE *stream,const char *name)
{
        if( fseeko(stream,offset,whence) ) {
                perror(name);
                exit(EXIT_FAILURE);
        }
}

FILE *
xfopen(const char *path,const char *mode)
{
        FILE *fp = fopen(path,mode);
        if( fp == NULL ) {
                perror(path);
                exit(EXIT_FAILURE);
        }
        return fp;
}
,

您可以删除git checkout .

^H

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...