我想在linux上写一个C程序,它不断刷新屏幕并实时更新(例如,类似于top终端中的命令)。谁能指出我正确的方向。
6 回答
要使其在终端类型之间保持可移植性,您需要使用诸如ncurses之类的库。查看该链接,它是一个详尽的教程。
这是一个在屏幕左上角打印不断增加的数字的基本程序:
#include <stdio.h>
#include <ncurses.h>
int main (void)
{
        /* compile with gcc -lncurses file.c */
        int c = 0;
        /* Init ncurses mode */
        initscr ();
        /* Hide cursor */
        curs_set (0);
        while (c < 1000) {
                /* Print at row 0, col 0 */
                mvprintw (0, 0, "%d", c++);
                refresh ();
                sleep (1);
        }
        /* End ncurses mode */
        endwin();
        return 0;
}
这就是你刷新窗口的方式。现在,如果您想按原样显示数据行,则显示的top数据需要以有序的数据结构维护(取决于您的数据,它可能像数组或链表一样简单)。您必须根据您的逻辑要求对数据进行排序,并在 aclear()或之后重新写入窗口(如上例所示) wclear()。
如果您在xterm或VT100兼容,您可以使用控制台代码,例如:
#include <stdio.h>
#include <unistd.h> /* for sleep */
#define update() printf("\033[H\033[J")
#define gotoxy(x, y) printf("\033[%d;%dH", x, y)
int main(void)
{
    update();
    puts("Hello");
    puts("Line 2");
    sleep(2);
    gotoxy(0, 0);
    puts("Line 1");
    sleep(2);
    return(0);
}
您几乎可以使用转义序列执行所有操作,但正如 wikipedia 中所指出的:ncurses优化屏幕更改,以减少使用远程 shell 时遇到的延迟。
Ncurses可能是要走的路。既然你说的是程序,那么ncurses,c,c++。调查这一切。但是,如果您打算只做一些与“shell”相关的事情,请使用 perl。
编辑:为了补充我的观点,这里有一些模块可以给你一个想法。
http://metacpan.org/pod/Curses::UI::Dialog::Progress
http://metacpan.org/pod/Smart::评论
window.clrtobot()
为了更好地衡量,呼吁诅咒清除整个窗口。
根据您的情况,您可以使用命令行上的“watch”命令来快速查看顶部。您还可以同时观看多个命令。
前任:
watch 'ls -l <somefile>; ps -fC <someprocess>; ./some_script'
正如其他人所说,您可能想查看 ncurses 库。但是,如果您不需要高级格式化,也许像这样简单的东西就足够了:
#include <stdio.h>
#include <unistd.h>
int main(void) {
    int number = 0;
    while (1) {
        ++number;
        printf("\rThe number is now %d.", number);
        fflush(stdout);
        sleep(1);
    }
    return 0;
}
除了使用 ncurses 库进行屏幕处理之外,如果您想“连续”和“实时”更新它,您可能还需要查看计时器和信号处理。timer_create()并且timer_settime()可以让您开始计时,然后您可以使用sigaction()设置处理函数来捕获SIGALRM信号并进行更新。
编辑:根据要求,这是一些示例代码:
#define TIMESTEP 200000000
timer_t SetTimer(void) {
    struct itimerspec new_its;
    struct sigevent sevp;
    timer_t main_timer;
    sevp.sigev_notify = SIGEV_SIGNAL;
    sevp.sigev_signo = SIGALRM;
    timer_create(CLOCK_REALTIME, &sevp, &main_timer);
    new_its.it_interval.tv_sec = 0;
    new_its.it_interval.tv_nsec = TIMESTEP;
    new_its.it_value.tv_sec = 0;
    new_its.it_value.tv_nsec = TIMESTEP;
    timer_settime(main_timer, 0, &new_its, NULL);
    return main_timer;
}
void SetSignals(void) {
    struct sigaction sa;
    /*  Fill in sigaction struct  */
    sa.sa_handler = handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    /*  Set signal handler  */
    sigaction(SIGALRM, &sa, NULL);
}
void handler(int signum) {
    switch (signum) {
    case SIGALRM:
        update_stuff();    /*  Do your updating here  */
        break;
    }
}