如何覆盖或编辑ruby CLI脚本中最后打印的行?

如何覆盖或编辑ruby CLI脚本中最后打印的行?,ruby,command-line,Ruby,Command Line,我试图构建一个脚本,在命令行上为我提供进度反馈。实际上,它只是为每一个第n步的进展画了一条新线。控制台看起来像 10:30:00 Parsed 0 of 1'000'000 data entries (0 %) 10:30:10 Parsed 1'000 of 1'000'000 data entries (1 %) 10:30:20 Parsed 2'000 of 1'000'000 data entries (2 %) [...] etc [...] 11:00:00 Parsed 1'00

我试图构建一个脚本,在命令行上为我提供进度反馈。实际上,它只是为每一个第n步的进展画了一条新线。控制台看起来像

10:30:00 Parsed 0 of 1'000'000 data entries (0 %)
10:30:10 Parsed 1'000 of 1'000'000 data entries (1 %)
10:30:20 Parsed 2'000 of 1'000'000 data entries (2 %)
[...] etc [...]
11:00:00 Parsed 1'000'000 of 1'000'000 data entries (100 %)
即使时间戳和进程号是虚构的,您也应该看到问题所在

我想做的是在命令行上更新一个progressbar,并记住线宽,从而实现“
wget
-style”

首先我想到了诅咒的用法,因为我在尝试学习C语言时已经动手了,但是我从来没有对它感到温暖过,而且我认为它过于臃肿,只是为了操纵几行。我也不需要任何颜色。另外,我发现的大多数其他库似乎都是专门用于着色的


有人能帮我解决这个问题吗?

也许可以将您的输出替换为:

print "Progress #{progress_var}%\r"

不久前,我创建了一个类作为状态文本,您可以在其上更改行中文本的部分内容。它可能对你有用

具有示例用法的类包括:

class StatusText
  def initialize(parms={})
    @previous_size = 0
    @stream = parms[:stream]==nil ? $stdout : parms[:stream]
    @parms = parms
    @parms[:verbose] = true if parms[:verbose] == nil
    @header = []
    @onChange = nil
    pushHeader(@parms[:base]) if @parms[:base]
  end

  def setText(complement)
    text = "#{@header.join(" ")}#{@parms[:before]}#{complement}#{@parms[:after]}"
    printText(text)
  end

  def cleanAll
    printText("")
  end

  def cleanContent
    printText "#{@parms[:base]}"
  end

  def nextLine(text=nil)
    if @parms[:verbose]
      @previous_size = 0
      @stream.print "\n"
    end
    if text!=nil
      line(text)
    end
  end

  def line(text)
    printText(text)
    nextLine
  end

  #Callback in the case the status text changes
  #might be useful to log the status changes
  #The callback function receives the new text
  def onChange(&block)
    @on_change = block
  end

  def pushHeader(head)
    @header.push(head)  
  end

  def popHeader
    @header.pop  
  end

  def setParm(parm, value)
    @parms[parm] = value
    if parm == :base
      @header.last = value
    end
  end

  private
  def printText(text)
    #If not verbose leave without printing
    if @parms[:verbose]
      if @previous_size > 0
        #go back
        @stream.print "\033[#{@previous_size}D"
        #clean
        @stream.print(" " * @previous_size) 
        #go back again
        @stream.print "\033[#{@previous_size}D"
      end
      #print
      @stream.print text
      @stream.flush
      #store size
      @previous_size = text.gsub(/\e\[\d+m/,"").size
    end
    #Call callback if existent
    @on_change.call(text) if @on_change
  end
end

a = StatusText.new(:before => "Evolution (", :after => ")")

(1..100).each {|i| a.setText(i.to_s); sleep(1)}
a.nextLine
只需复制、粘贴到ruby文件中,然后进行尝试。我使用转义序列来重新定位光标

这个类有很多我当时需要的特性(比如在状态栏中堆积元素),你可以用它们来补充你的解决方案,或者你可以把它清理到核心


我希望它能有所帮助。

与此同时,我发现了一些给我一个进度条的宝石,我将在这里列出它们:

我试了一个和那个,它们都有优点和缺点,但也都适合我的需要。也许我将来会分叉并扩展其中一个


我希望这一条能帮助其他人更快地找到我搜索了几个月的内容。

这将是第一步,但这并不是我真正想要的,因为我说过我想要一个wget样式的progressbar,对于这个bar,我需要知道控制台的宽度。即使我可以计算一些固定值,这也会在使用较小的控制台时造成麻烦,或者在使用较大的控制台时看起来很难看。另外,使用
print“\r”
只允许覆盖最后一行,但有时我想覆盖2行、3行甚至更多行(这就是为什么我在主题中写了行而不是行),这似乎也仅限于最后一行,此外,它也没有给我任何可能性来确定控制台缓冲区的宽度。修改确实限于最后一行。方法nextLine只添加一个新行,但不允许对前一行进行修改。我还没有考虑如何确定控制台缓冲区的宽度。正如我所说,这是我在我的一个项目中使用的一种解决方案,我相信它能够很好地适应你想要的。即使我接受了,我也会继续使用诅咒方法,并在之前做一些研究。如果我能学到任何能帮助别人解决类似问题的东西,我会自我回答。谢谢你的帮助。