端末シーケンスで既存の行を上書きする方法

端末シーケンスで既存の行を上書きする方法

したがって、wgetWebページをインポートすると、ファイルがどれだけダウンロードされたかを示すステータスバーが表示されます。次のようになります。

25%[=============>______________________________________] 25,000 100.0K/s (下線は空白です。その中に複数の連続した空白を入れる方法がわかりません)

ただし、stdoutに別の行を作成して別の進行状況バーを追加する代わりに、次のように更新します。

50%[===========================>________________________] 50,000 100.0K/s

これもwget唯一の例ではありません。たとえば、何かをパイプで接続しlessて終了すると、以前に実行したコマンドの結果とともに元のプロンプトがそのまま残ります。まるであなたが去っていないようです。

だから私の質問は、これが何であるか、どのように実装するのか、そして一度に1つの行に対してしか機能しません。 Cで使えますか?

答え1

まず第一に、あなたの問題はbashには関係ありませんが、端末に関連しています。端末はプログラムのテキストを表示して応答し、bash自体はプログラムの起動後にそれを制御する方法はありません。

端末は、色、フォント、カーソル位置などを制御する制御シーケンスを提供します。標準化された端末シーケンスのリストについては、以下を参照してください。 http://www.termsys.demon.co.uk/vtansi.htmたとえば、次のことができます。

  • カーソルを行の先頭に置く
  • 次に、その行を削除します。
  • 新しい行を書く

進行状況バーを作成します。

高度な端末エスケープシーケンスは、通常、Eterm や xterm などの端末ごとに異なります。呪い- エスケープシーケンスを使用する必要がないように端末と対話型プログラムを生成するためのプログラミングライブラリです。

端末シーケンスで既存の行を上書きする方法

echo long text
sleep 1
printf "\033[1A"  # move cursor one line up
printf "\033[K"   # delete till end of line
echo foo

端末シーケンスなしで既存の行を上書きする方法

簡単な解決策は、最後に改行文字を書くのではなく、デフォルトでカーソルを行の先頭にリセットするキャリッジリターン文字を書くことです。たとえば、次のようになります。

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

または、キャリッジリターンを使用する\rと、カーソルが行の先頭に置かれ、行の内容を上書きできます。

lessまたは同じバッファ間の切り替えvi

この動作は、less高度な端末機能、つまり代替画面によっても発生します。

VT102モードには、ウィンドウの表示領域と同じサイズの代替画面バッファを有効または無効にするために使用されるエスケープシーケンスがあります。有効にすると、現在の画面が保存され、代替画面に置き換えられます。ウィンドウの上部からスクロールした行の保存は、通常の画面が復元されるまで無効になります。 xtermのtermcap(5)エントリを使用すると、ビジュアルエディタvi(1)が編集用の代替画面に切り替え、終了時に画面を復元できます。ポップアップメニュー項目を使用すると、切り取りと貼り付け操作のための一般画面と代替画面を簡単に切り替えることができます。

http://rosettacode.org/wiki/Terminal_control/Preserve_screen次の方法で直接実行できるいくつかの例がリストされています。出力またはいくつかのエスケープシーケンスを介して。

答え2

echo文字列に改行文字を自動的に追加する代わりに、--carriage戻り文字を使用してカーソルを現在の行の先頭に送信します。printf "%s\r" whatever例:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""

答え3

このトピックを探している人も一度見てください。Bash プロンプト HOWTO - カーソル移動

例:

- Position the Cursor:
  \033[<L>;<C>H
     Or
  \033[<L>;<C>f
  puts the cursor at line L and column C.
- Move the cursor up N lines:
  \033[<N>A
- Move the cursor down N lines:
  \033[<N>B
- Move the cursor forward N columns:
  \033[<N>C
- Move the cursor backward N columns:
  \033[<N>D

- Clear the screen, move to (0,0):
  \033[2J
- Erase to end of line:
  \033[K

- Save cursor position:
  \033[s
- Restore cursor position:
  \033[u

Cのいくつかの例:

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void lineDown(short int times) {
  printf("\033[%iB", times);
}

プログラム例:

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

void saveCursorPosition() {
  printf("\033[s");
}

void restoreCursorPosition() {
  printf("\033[u");
}

void lineUP(short int times) {
  printf("\033[%iA", times);
}

void moveCursorBackwards(short int times) {
  printf("\033[%iD", times);
}

void printMainText() {

  printf("\n ╔═══════════════════════════════╗");
  printf("\n ║                               ║");
  printf("\n ║ Progress Bar                  ║");
  printf("\n ║                               ║");
  printf("\n ║ []                            ║");
  printf("\n ║                               ║");
  printf("\n ║ Press Ctrl+C to close         ║");
  printf("\n ║                               ║");
  printf("\n ╚═══════════════════════════════╝\n");

}

int main(int argc, char **argv) {

  printMainText();

  for (int progress=0; progress <= 10; progress++) {

    saveCursorPosition();
    lineUP(5);

    printf("\r ║     [");
    fflush(stdout);

    for (int i=0; i<progress; i++) {
      printf("=>]");
      fflush(stdout);
      moveCursorBackwards(2);
    }

    moveCursorBackwards(progress + 5);

    printf("%i%%", progress * 10);
    fflush(stdout);

    restoreCursorPosition();

    sleep(1);

  }

  return 0;

}

関連情報