2010-02-05 49 views
7

Tôi đã viết một chương trình dòng lệnh sẽ có thanh trạng thái, giống như wget.xóa đầu ra của thiết bị đầu cuối trên linux

Vấn đề chính mà tôi đang gặp phải là: làm thế nào để xóa những gì tôi đã gửi vào stdout/stderr?

Tôi đã có ý tưởng: sử dụng backspace char '\ b' và xóa đầu ra mà tôi đã gửi. Đó có phải là cách tốt nhất không? Đó là cách duy nhất? Có cách nào tốt hơn?

PS: Tôi không muốn sử dụng bất kỳ thứ gì như ncurses. Đồng bằng cũ C xin vui lòng.

Cảm ơn


EDIT:

Tôi có thể cũng đi lên và/hoặc xuống? Ví dụ: Tôi có 10 dòng đầu ra, tôi muốn thay đổi dòng thứ 3 từ Doing ABC thành ABC: Done. Làm thế nào tôi có thể làm điều đó?

Ngoài ra, bất kỳ ai cũng có thể đăng thêm chi tiết về nhân vật VT102 là gì? Khả năng của nó là gì? Xin vui lòng gửi các liên kết tốt về điều này nếu bạn có bất kỳ.

Cảm ơn

+0

Google 'vt100 codes' hoặc' vt102 codes'. –

+0

Xem câu trả lời cho câu hỏi này về việc xóa đầu ra của chương trình đầu cuối - http://stackoverflow.com/questions/1348563/clearing-output-of-a-terminal-program-linux-c-c – jschmier

Trả lời

3

Sử dụng '\ r' để quay lại đầu dòng và có thể viết lại toàn bộ dòng.

Tìm chuỗi điều khiển VT102 - đây là các chuỗi ký tự ESC ... để điều khiển thiết bị đầu cuối của bạn.

+2

câu trả lời của bạn giải quyết hoàn toàn câu hỏi ban đầu của tôi, mặc dù tôi bị cám dỗ để ncurses, bây giờ tôi đã đọc câu trả lời của John .. – jrharshath

0

Đây là thanh tiến trình để 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""%"; 
} 
+1

không muốn bash. muốn cho c. không bash. chỉ C. c. – jrharshath

+6

Hoặc ... bạn có thể đọc nó, và sau đó suy nghĩ về những gì bạn đọc. Bạn có thể nhận ra rằng nó sẽ cho bạn biết cách hoạt động của nó và với một chút suy nghĩ khác, bạn có thể thực hiện triển khai c của riêng mình. Chỉ là một ý nghĩ. –

1

Một biến thể nhẹ trên giải pháp của riêng bạn:

Bạn cũng có thể in một trở về vận chuyển (\r), trong đó sẽ đưa bạn trở về đầu dòng.

2

Ngoài ra còn có khả năng sử dụng Ncurses, là thư viện dành cho giao diện người dùng văn bản, trong đó loại hành vi này sẽ có một số hỗ trợ. Tuy nhiên, nó có thể là quá mức cần thiết cho một cái gì đó như thế này.

+0

Đúng như câu trả lời của bạn, người hỏi đã quyết định rằng họ không muốn sử dụng nó. –

6

Các ký tự điều khiển định dạng cơ bản là backspace (\ b), tab (\ t), dòng mới (\ n) và trả về vận chuyển (\ r). Nếu bạn cần nhiều hơn thế thì bạn có thể sử dụng các trình tự thoát ANSI X3.64/ISO/IEC 6429/ECMA-48; ít nhất the VT100 subset được công nhận bởi hầu hết các thiết bị đầu cuối hiện đại và giả lập. Một lợi thế của việc sử dụng ncurses là nó sẽ tìm kiếm các khả năng của thiết bị đầu cuối cụ thể của bạn và do đó nó sẽ hoạt động ngay cả khi thiết bị đầu cuối của bạn sử dụng một tập hợp các chuỗi thoát khác nhau.

+0

+1: Câu trả lời hay nhất; nên đã được chấp nhận. –

5

Bạn phải nhớ rằng theo như thường lệ stdio thường xuyên có liên quan, stdout chỉ là một luồng byte không có đặc tính hiển thị vốn có; điều đó phụ thuộc vào thiết bị đích, có thể là bất cứ thứ gì từ một thiết bị đầu cuối kiểu VT100 thông thường đến một đầu cuối bản cứng tới một máy in được trang bị cho một bản vẽ cho bất kỳ thứ gì.

IMO, bạn đang xa hơn sử dụng thư viện như ncurses tốt hơn là cố gắng cùng nhau mã quản lý hiển thị của riêng bạn với mã thoát VT100, ngay cả đối với một tác vụ tương đối đơn giản như thế này. Tôi biết bạn muốn gắn bó với "đồng bằng C cũ", nhưng đây là một nhiệm vụ nằm ngoài giới hạn của đồng bằng C.

+1

Làm thế nào để bạn biết đầu ra tty hiểu mã vt100? Đồng ý với các thư viện (3) (hoặc biến thể). Đối với một cái gì đó như thế này, nó khá đơn giản – mpez0

0

Giới thiệu về thanh tiến trình: một cái gì đó như thế này?

#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); 
}; 

Lưu ý: unistd.h và điều ngủ là chỉ giả mạo tiến trình của một thao tác, mã vạch tiến trình tự sử dụng thư viện chuẩn. Giả định duy nhất của nó về luồng đầu ra là \ b thực sự nhận được ký tự viết trước đó. Tôi đã thử nó thành công trên Windows và Linux (với gnome-terminal), không biết nếu nó không hoạt động đúng với một số trình mô phỏng đầu cuối. Xin lỗi vì số lượng nhận xét quá mức, tôi đã viết nó cho một diễn đàn khác, nơi tôi cần giải thích một cách chi tiết mỗi dòng mã cho một người mới sử dụng C.

Các vấn đề liên quan