Вывод хода выполнения на месте в терминале или консоли

Когда вы запускаете git clone, он обновляет прогресс на месте. Например, процент полученных объектов меняется на месте.

user@athena:~/cloj/src$ git clone git://git.boinkor.net/slime.git
Initialized empty Git repository in /home/user/cloj/src/slime/.git/
remote: Counting objects: 15936, done.
remote: Compressing objects: 100% (5500/5500), done.
Receiving objects:  28% (4547/15936), 3.16 MiB | 165 KiB/s

Как это осуществляется? Использует ли он ncurses или что-то еще более простое, например, некоторую комбинацию символов возврата и обычного вывода символов?

Меня особенно интересует, как такого рода консольный вывод может быть выполнен из Ruby.

РЕДАКТИРОВАТЬ

Ответ на мой первоначальный вопрос. Но вот дополнение. Когда вы используете MPlayer, например, он обновляет не только строку, чтобы показать текущий прогресс, но и предыдущую строку (например, когда вы нажимаете паузу).

 =====  PAUSE  =====
A:  79.9 (01:19.9) of 4718.0 ( 1:18:38.0)  0.3% 

Как бы вы обновили две строки вывода на месте?


person dan    schedule 25.02.2010    source источник
comment
Также взгляните на stackoverflow.com/questions/613305/   -  person vladr    schedule 28.02.2010
comment
Этот вопрос и связанный с ним ответ — именно то, что делает переполнение стека замечательным. Спасибо за них.   -  person num1    schedule 21.03.2011


Ответы (5)


Используйте возврат каретки. '\r' обычно должен работать.

person Community    schedule 25.02.2010
comment
Вот пример: 10.times{|i| STDOUT.write "\r#{i}"; sleep 1} - person Mladen Jablanović; 25.02.2010
comment
Спасибо. Но почему \r имеет такой эффект в Unix? - person dan; 25.02.2010
comment
Мне нужно было добавить $stdout.flush, чтобы он работал в Ubuntu следующим образом: 10.times { |i| $stdout.write "\r#{i}"; $stdout.flush; sleep 1 } - person ; 23.12.2011

git/progress.c

...
        eol = done ? done : "   \r";
...
                fprintf(stderr, "...%s", ..., eol);
                fflush(stderr);

Git просто выдает возврат каретки и не переводит строку, что терминал интерпретирует как «перейти к первому столбцу».

person ephemient    schedule 25.02.2010

Вам придется использовать другой метод (например, Curses), чтобы обновить две строки на месте.

ablogaboutcode.com | web.archive.org

...и...

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/curses/rdoc/Curses.html

person Ivan Black    schedule 01.04.2013
comment
Ссылка на статью в блоге мертва. Пожалуйста, оберните ваши ссылки веб-архивом. - person Overbryd; 23.11.2016
comment
@Overbryd, он не умер. Но его поведение непредсказуемо. - person Ivan Black; 23.11.2016

Я написал небольшой класс для обновления многострочного вывода:

class ConsoleReset
  # Unix
  # Contains a string to clear the line in the shell
  CLR = "\e[0K"
  # ANSI escape sequence for hiding terminal cursor
  ESC_CURS_INVIS = "\e[?25l"
  # ANSI escape sequence for showing terminal cursor
  ESC_CURS_VIS   = "\e[?25h"
  # ANSI escape sequence for clearing line in terminal
  ESC_R_AND_CLR  = "\r#{CLR}"
  # ANSI escape sequence for going up a line in terminal
  ESC_UP_A_LINE = "\e[1A"

  def initialize
    @first_call = true
  end

  def reset_line(text = '')
    # Initialise ANSI escape string
    escape = ""

    # The number of lines the previous message spanned
    lines = text.strip.lines.count - 1

    # Clear and go up a line
    lines.times { escape += "#{ESC_R_AND_CLR}#{ESC_UP_A_LINE}" }

    # Clear the line that is to be printed on
    # escape += "#{ESC_R_AND_CLR}"

    # Console is clear, we can print!
    STDOUT.print escape if !@first_call
    @first_call = false
    print text
  end

  def hide_cursor
    STDOUT.print(ESC_CURS_INVIS)
  end

  def show_cursor
    STDOUT.print(ESC_CURS_VIS)
  end

  def test
    hide_cursor

    5.times do |i|
      line = ['===========================================']
      (1..10).each do |num|
        line << ["#{num}:\t#{rand_num}"]
      end
      line << ['===========================================']
      line = line.join("\n")
      reset_line(line)
      sleep 1
    end

    show_cursor

    puts ''
  end

  private
    def rand_num
      rand(10 ** rand(10))
    end
end

На основе prydonius/spinning_cursor. См. метод test для примера использования.

person hlcs    schedule 10.02.2017

Существует несколько библиотек curses для Ruby. Я считаю, что rbbcurse является наиболее поддерживаемым.

person Farrel    schedule 25.02.2010