web-dev-qa-db-ja.com

現在印刷されているコンソール行を消去します

Cで現在印刷されているコンソール行を消去するにはどうすればよいですか? Linuxシステムで作業しています。例えば ​​-

printf("hello");
printf("bye");

こんにちはの代わりに同じ行に別れを印刷したいです。

60
Peter

VT100エスケープコード を使用できます。 xtermを含むほとんどの端末はVT100に対応しています。行を消去する場合、これは^[[2K。 Cでは、次のようになります。

printf("%c[2K", 27);
60
mouviciel

\rcarriage return )を使用して、カーソルを行の先頭に戻すことができます。

printf("hello");
printf("\rbye");

これは、同じ行にbyeを出力します。ただし、既存の文字は消去されません。また、byehelloよりも短いため、byelo。それを消去するには、新しい文字を長くして余分な文字を上書きします。

printf("hello");
printf("\rbye  ");

または、最初にスペースをいくつか削除してから、新しい文字列を印刷します。

printf("hello");
printf("\r          ");
printf("\rbye");

それはhelloを印刷し、行の先頭に移動してスペースで上書きし、再び先頭に戻ってbye

53
Andre Miller

いくつかの価値のある微妙な...

_\33[2K_は、カーソルが現在ある行全体を消去します

_\033[A_はカーソルを1行上に移動しますが、同じ列では、行の先頭ではありません

_\r_はカーソルを行の先頭に移動します(rは巻き戻し用です)しません何でも消去します

特にxtermでは、上記の返信を試みましたが、行を消去して最初からやり直す唯一の方法は、シーケンスです(@ Stephan202と@vlpと@mantalによって投稿された上記のコメントから)_\33[2K\r_

実装ノートでは、各fprintf()の最後に改行文字_'\n'_を使用していなかったため、たとえばカウントダウンシナリオで適切に動作させるために、fflush()毎回ストリーム(コンテキストを提供するため、stdoutをリダイレクトせずにLinuxマシンでforkを使用してxtermを起動しました。バッファリングされたFILEポインターfdfileに非-ファイル記述子のブロック私は、擬似端末アドレス(私の場合は_/dev/pts/21_)に座っていました:

_fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);
_

\ 33 [2Kシーケンスの両方を使用して行を消去し、その後に_\r_巻き戻しシーケンスを使用して、行の先頭にカーソルを再配置したことに注意してください。 _'\n'_の最後に改行文字がないため、各fflush()の後にfprintf()が必要でした。 fflush()を必要とせずに同じ結果を得るには、追加のシーケンスが必要です。

_fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);
_

書き込みたい行のすぐ上の行に何かがある場合、最初のfprintf()で上書きされることに注意してください。最初の行を1行上に移動するには、上記の余分な行を残す必要があります。

_i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
    fprintf(fdfile, "\033[A\33[2KT\rT minus %d seconds...\n", i);
    i--;
    sleep(1);
}
_
33
J-a-n-u-s

\ bを使用して行を削除できます

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("\b");
}
printf("bye");
4
Alexander Egger

通常、文字列の末尾に「\ r」がある場合、改行なしで復帰のみが印刷されます。次のものがある場合:

printf("fooooo\r");
printf("bar");

出力は次のようになります。

barooo

私が提案できる1つのこと(おそらく回避策)は、すべてのスペース文字に初期化され、印刷前に毎回「\ r」で終了するNULL終了固定サイズ文字列を持ち、strcpyを使用して文字列をコピーすることですそれは(改行なしで)、その後の印刷ごとに前の文字列を上書きします。このようなもの:

char str[MAX_LENGTH];        
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string);       // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);

エラーチェックを実行して、my_stringは常にstrよりも少なくとも1つ短くなりますが、基本的な考え方は理解できます。

3
Ashwin

iは、char配列の単語を反復処理します。 jはワード長を追跡します。 "\b \b"は、行に戻るときにWordを消去します。

#include<stdio.h>

int main()
{
    int i = 0, j = 0;

    char words[] = "Hello Bye";

    while(words[i]!='\0')
    {
        if(words[i] != ' ') {
            printf("%c", words[i]);
        fflush(stdout);
        }
        else {
            //system("ping -n 1 127.0.0.1>NUL");  //For Microsoft OS
            system("sleep 0.25");
            while(j-->0) {
                printf("\b \b");
            }
        }

        i++;
        j++;
    }

printf("\n");                   
return 0;
}
2
Paul T

このスクリプトは、例のためにハードコーディングされています。

#include <stdio.h>

int main ()
{

    //write some input  
    fputs("hello\n",stdout);

    //wait one second to change line above
    sleep(1);

    //remove line
    fputs("\033[A\033[2K",stdout);
    rewind(stdout);

    //write new line
    fputs("bye\n",stdout);

    return 0;
}

source については、ここをクリックしてください。

1
vlp

ここで作業できる簡単なトリックがありますが、印刷する前に準備が必要です。印刷したいものを変数に入れてから印刷する必要がありますので、文字列を削除する長さを知ることができます。

#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc

using namespace  std;

int main(){

//create string variable

string str="Starting count";

//loop for printing numbers

    for(int i =0;i<=50000;i++){

        //get previous string length and clear it from screen with backspace charactor

        cout << string(str.length(),'\b');

        //create string line

        str="Starting count " +to_string(i);

        //print the new line in same spot

        cout <<str ;
    }

}
1
Aylian Craspa

windows 10では、現在のコンソールでVT100モードを有効にして次のようにエスケープシーケンスを使用することにより、VT100スタイルを使用できます。

#include <windows.h>
#include <iostream>

#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN  0x0008

int main(){

  // enabling VT100 style in current console
  DWORD l_mode;
  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  GetConsoleMode(hStdout,&l_mode)
  SetConsoleMode( hStdout, l_mode |
            ENABLE_VIRTUAL_TERMINAL_PROCESSING |
            DISABLE_NEWLINE_AUTO_RETURN );

  // create a waiting loop with changing text every seconds
  while(true) {
    // erase current line and go to line begining 
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second .";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ..";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ...";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ....";
 }

}

次のリンクを参照してください: windows VT1

0
user2019716

この古いスレッドを見つけて、実際の行を空白にするための何らかのエスケープシーケンスを探しました。

Printfが書き込まれた文字の数を返すという考えに誰も気付いていなかった(または見落としていた)のは非常に面白いことです。したがって、 '\ r' + printfが返しただけの空白文字を印刷するだけで、前に書いたテキストを正確に空白にすることができます。

int BlankBytes(int Bytes)
{
                char strBlankStr[16];

                sprintf(strBlankStr, "\r%%%is\r", Bytes);
                printf(strBlankStr,"");

                return 0;
}

int main(void)
{
                int iBytesWritten;
                double lfSomeDouble = 150.0;

                iBytesWritten = printf("test text %lf", lfSomeDouble);

                BlankBytes(iBytesWritten);

                return 0;
}

私はVT100を使用できないので、その解決策に固執しなければならないようです

0
David
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye  "

上記のコマンドの機能:

  1. Helloが出力され、カーソルは「o」のままになります(\ cを使用)

  2. その後、1秒間待機します(スリープ1)

  3. その後、helloをbyeに置き換えます(\ rを使用)

NOTE : Using ";", We can run multiple command in a single go.

0
Ayush Mahajan