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

标签 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'000'000 of 1'000'000 data entries (100 %)

即使时间戳和进度数字是虚构的,您也应该看到问题。

我想要的是“wget-style”,并在命令行上更新进度条,并考虑到线宽。

首先我想到了使用curses,因为我在尝试学习C时已经上手了,但我从来没有对它感兴趣,而且我认为它对于仅仅操作几行代码来说是臃肿的。我也不需要任何着色。我发现的大多数其他库似乎都是专门用于着色的。

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

最佳答案

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

具有示例用途的类是:

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​​ 文件中并尝试一下。我使用转义序列来重新定位光标。

该类具有我当时需要的许多功能(例如在状态栏中堆积元素),您可以使用它们来补充您的解决方案,或者您也可以直接清理它的核心。

希望对您有所帮助。

关于ruby - 如何覆盖或编辑 ruby​​ CLI 脚本中最后打印的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6677135/

相关文章:

ruby-on-rails - 推送到Heroku时“different prefix”错误和“Lockfile is unreadable”错误

linux - 是否可以在有关目录或文件的目录中添加注释?

linux - 下载 Wget 以外的文件的命令

macos - Ubuntu 上的 findutils 4.4.x 不允许我指定 `depth` 选项

ruby - 如何重命名 S3 存储桶中的文件夹?

ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前?

ruby-on-rails - 从 Ruby on Rails 中的 collection.map 中排除选项?

ruby-on-rails - Heroku 推送问题第 2 部分 - Postgresql - PGError 关系不存在 - Ruby on Rails

ios - 如何从命令行在 iOS 模拟器中设置默认设备

go - 如何在golang中以命令行格式解析字符串