簡體   English   中英

擦除linux上的終端輸出

[英]erasing terminal output on linux

我正在編寫一個命令行程序,它將有一個狀態欄,就像wget一樣。

我面臨的主要問題是:如何刪除我已經發送到stdout / stderr的內容?

我有想法:使用退格字符'\\ b'並刪除我發送的輸出。 這是最好的方式嗎? 這是唯一的方法嗎? 有沒有更好的辦法?

PS:我不想使用像ncurses這樣的東西。 平原老C請。

謝謝


編輯:

我也可以往上走/走嗎? 示例:我有10行輸出,我想將第3行從Doing ABC更改為ABC: Done 我怎樣才能做到這一點?

此外,任何人都可以發布有關VT102字符的更多詳細信息嗎? 它的功能是什么? 如果您有任何好的鏈接,請在此發布。

謝謝

基本格式控制字符是退格(\\ b),制表符(\\ t),換行符(\\ n)和回車符(\\ r \\ n)。 如果您需要更多,那么您可以使用ANSI X3.64 / ISO / IEC 6429 / ECMA-48轉義序列; 至少VT100子集被大多數現代終端和仿真器識別。 使用ncurses的一個優點是它將查找特定終端的功能,因此即使您的終端使用一組不同的轉義序列它也能正常工作。

您必須記住,就常規stdio例程而言, stdout只是一個字節流,沒有固有的顯示特性; 這取決於目標設備,可以是從常規VT100風格的終端到硬拷貝終端,到單張紙打印機,到繪圖儀等等。

IMO,使用像ncurses這樣的庫比使用VT100轉義代碼破解自己的顯示管理代碼好得多,即使對於這樣一個相對簡單的任務也是如此。 我知道你想堅持使用“普通老C”,但這是一項超出普通老C范圍的任務。

使用'\\ r'返回行的開頭並可能重寫整行。

尋找VT102控制序列 - 這些是字符序列ESC ...來控制你的終端。

還有使用Ncurses的可能性, Ncurses是Textual UI的庫,這種行為應該有一些支持。 但是,這樣的事情可能有點過分。

您自己的解決方案略有不同:

您還可以打印回車符( \\r ),它將返回到行的開頭。

它是bash的進度條。

function gauge()
{
        progress="$1"
        total="$2"
        width=`tput cols`
        let gwidth=width-7

        if [ "$total" == "0" ]; then
                percent=100
        else
                set +e
                let percent=progress*100/total;
                set -e
        fi

        set +e
        let fillcount=percent*gwidth/100
        let nofillcount=gwidth-fillcount
        set -e

        fill="";
        if [ "$fillcount" -gt "0" ]; then
                for i in `seq $fillcount`; do
                        fill="$fill""|"
                done
        fi;
        nofill=""
        if [ "$nofillcount" -gt "0" ]; then
                for i in `seq $nofillcount`; do
                        nofill="$nofill"" ";
                done
        fi
        echo -e -n "\r[""$fill""$nofill""] ""$percent""%";
}

關於進度條:這樣的事情?

#include <stdio.h>
#include <unistd.h>

typedef enum
{
    false=0,
    true=!false
} bool;

typedef struct
{
    /* Start delimiter (e.g. [ )*/
    char StartDelimiter;
    /* End Delimiter (e.g. ] )*/
    char EndDelimiter;
    /* Central block (e.g. = )*/
    char Block;
    /* Last block (e.g. > ) */
    char CurBlock;
    /* Width of the progress bar (in characters) */
    unsigned int Width;
    /* Maximum value of the progress bar */
    double Max;
    /* True if we have to print also the percentage of the operation */
    bool PrintPercentage;
    /* True if the bar must be redrawn;
       note that this must be just set to false before the first call, the function then will change it by itself.  */
    bool Update;
} ProgressBarSettings;

/* Prints/updates the progress bar */
void PrintProgressBar(double Pos, ProgressBarSettings * Settings);
/* Inits the settings of the progress bar to the default values */
void DefaultProgressBar(ProgressBarSettings * Settings);

int main()
{
    int i;
    /* Init the bar settings */
    ProgressBarSettings pbs;
    DefaultProgressBar(&pbs);
    pbs.Max=200;
    pbs.Width=60;
    printf("Progress: ");
    /* Show the empty bar */
    PrintProgressBar(0,&pbs);
    for(i=0;i<=pbs.Max;i++)
    {
        /* Wait 50 msec */
        usleep(50000);
        /* Update the progress bar */
        PrintProgressBar(i,&pbs);
    }
    puts(" Done");
    return 0;
}

/* Inits the settings of the progress bar to the default values */
void DefaultProgressBar(ProgressBarSettings * Settings)
{
    Settings->StartDelimiter='[';
    Settings->EndDelimiter=']';
    Settings->Block='=';
    Settings->CurBlock='>';
    Settings->PrintPercentage=true;
    Settings->Update=false;
    Settings->Max=100;
    Settings->Width=40;
}

/* Prints/updates the progress bar */
void PrintProgressBar(double Pos, ProgressBarSettings * Settings)
{
    /* Blocks to print */
    unsigned int printBlocks=(unsigned int)(Settings->Width*Pos/Settings->Max);
    /* Counter */
    unsigned int counter;
    /* If we are updating an existing bar...*/
    if(Settings->Update)
    {
        /* ... we get back to its first character to rewrite it... */
        for(counter=Settings->Width+2+(Settings->PrintPercentage?5:0);counter;counter--)
            putchar('\b');
    }
    else
        Settings->Update=true; /* next time we'll be updating it */
    /* Print the first delimiter */
    putchar(Settings->StartDelimiter);
    /* Reset the counter */
    counter=Settings->Width;
    /* Print all the blocks except the last; in the meantime, we decrement the counter, so in the end we'll have
       the number of spaces to fill the bar */ 
    for(;printBlocks>1;printBlocks--,counter--)
        putchar(Settings->Block);
    /* Print the last block; if the operation ended, use the normal block, otherwise the one for the last block */
    putchar((Settings->Max==Pos)?Settings->Block:Settings->CurBlock);
    /* Another block was printed, decrement the counter */ 
    counter--;
    /* Fill the rest of the bar with spaces */
    for(;counter;counter--)
        putchar(' ');
    /* Print the end delimiter */
    putchar(Settings->EndDelimiter);
    /* If asked, print also the percentage */
    if(Settings->PrintPercentage)
        printf(" %3d%%",(int)(100*Pos/Settings->Max));
    /* Flush the output buffer */
    fflush(stdout);
};

注意:unistd.h和usleep的事情只是偽造一個操作的進度,進度條碼本身只是使用標准庫。 它對輸出流的唯一假設是\\ b實際上到達之前的書寫字符。 我在Windows和Linux(使用gnome-terminal)上成功嘗試過,不知道它是否與某些終端模擬器無法正常工作。 對於過多的評論感到抱歉,我把它寫在另一個論壇上,我需要將一行代碼解釋為C新手。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM