微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从 groovy 脚本调用的外部进程处理多行输出的最佳方法?

如何解决从 groovy 脚本调用的外部进程处理多行输出的最佳方法?

我使用这种方法

def runProcess(List cmd) {
  def process = cmd.execute()
  def output = new StringWriter(),error = new StringWriter()
  process.waitForProcessOutput(output,error)
  def exitCode = process.exitValue()
  if (exitCode) {
    throw new Exception("Error: $error with code: $exitCode")
  }
  return output.toString().split()
}

运行可以返回一行或多行输出的外部进程。

有时我需要检查每一行并在找到时返回匹配项。首先,我尝试使用 eachLine 闭包,但发现我无法从中返回 (Can you break from a Groovy "each" closure?):

def sample() {
  String tagName = ""
  def tags = runProcess(["git","tag"])
  tags.eachLine { tag -> 
    println "tag $tag"
    if(tag = "mytag") {
      tagName = tag
      // Cannot return from a eachLine closure :-(
      return tag
    }
  }
  return tagName
}

上面的方法可行,但如果我有 1000 行,它将遍历所有行 - 因为 return 语句被忽略。

我现在正在尝试经典的 for 循环:

def sample() {

  def tags = runProcess(["git","tag"])
  println "tags.getClass() "  + tags.getClass() // this is java.lang.String
  String[] tagsArr = tags.split("\n");
  println "tags.getClass() "  + tagsArr.getClass() // this is [Ljava.lang.String
     
  if (tagsArr != null && tagsArr.length > 0) { // does NOT = true when tagsArr is empty :-(
     for (String tag : tagsArr) {
        def desc = shellCommand(["git","describe","--tags","$tag"])
        if(desc.trim() == "mytag") {
          println "Found tag: $tag at HEAD"
          return tag
        }
     }
  }
}

这非常冗长/丑陋,并且在 tagsArr不起作用(仍在调查此问题并感谢任何输入!)。

关于如何更好地处理调用外部进程的多行输出有什么建议吗?

同样来自上面:

return output.toString().split()

好像不太对……

我也看过:

http://konstructcomputers.blogspot.com/2013/12/groovy-line-by-line-process-output.html

看起来相当冗长/广泛。我希望 groovy 提供一些最小的方法来避免这种“低级”样板代码

旁注。有趣的是这个页面

http://docs.groovy-lang.org/latest/html/documentation/working-with-io.html

没有提到 waitForProcessOutput,我认为这是从外部进程获取输出的最可靠方法

更新示例(使用 readLines 和 find)

下面是基于以下建议的更新示例。我修改了原始示例以使其更清晰。

预期结果 = 注释

$ git for-each-ref refs/tags
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/001
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/002
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/003
706a21e04441c43e2b0372bd8607be74c0377690 tag    refs/tags/annotated
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/lightweight

使用 find() 和 split()(工作)

def runProcess(List cmd) {
  def process = cmd.execute()
  def outputWriter = new StringWriter(),errorWriter = new StringWriter()
  process.waitForProcessOutput(outputWriter,errorWriter)
  String output = outputWriter.toString()
  String error = errorWriter.toString()
  int exitCode = process.exitValue()
  if (exitCode) {
    throw new Exception("Error: $error exit code: $exitCode")
  }
  // Notice split()
  return output.split()
}

def sample() {
  def tags = runProcess(["git","tag","--points-at","HEAD"])
  def result = tags.find{tag -> 
    def tagType = runProcess(["git","cat-file","-t","$tag"])
    if(tagType[0] == "tag") {
      return tag
    }
  }
  return result
}

assert(result == "annotated")

readLines() 和 find()(同样有效)

def runProcess(List cmd) {
  def process = cmd.execute()
  def outputWriter = new StringWriter(),errorWriter)
  String output = outputWriter.toString()
  String error = errorWriter.toString()
  int exitCode = process.exitValue()
  if (exitCode) {
    throw new Exception("Error: $error exit code: $exitCode")
  }
  // Notice NO split()
  return output
}

def sample() {
  def tags = runProcess(["git","HEAD"])

  def result = tags.readLines().find{ tag ->
    def tagType = runProcess(["git","$tag"])
    if(tagType.trim()  == "tag") {
      return tag
    }
  }
  return result
}

assert(result == "annotated")

解决方法

String sample() {
  def tags = runProcess(["git","tag"]) // expected multiline string to be returned
  tags.readLines().find{tag->
    def desc = ...
    return desc=="mytag" // will break on first true returned
  }
}

这是一个可以在任何在线控制台中运行的测试脚本:

def tags = '''
aaa
bbb
ccc
'''

def found = tags.readLines().find{tag->
    return "BBB" ==  tag.toUpperCase()
}

println "found: ${found}"

https://groovyconsole.appspot.com/edit/5201583847505920?execute

另一个基于更新问题的示例:

def output = '''
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/001
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/002
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/003
706a21e04441c43e2b0372bd8607be74c0377690 tag    refs/tags/annotated
67a27fec636a12346f391c67be01a0c8c0e1b7b8 commit refs/tags/lightweight
'''

def tagname = output
                .readLines()
                .findAll()             //keep only non-empty lines
                .collect{it.split()}   //split each line by spaces
                .findAll{it[1]=='tag'} //find all items with 'tag'
                .findResult{tag->
                    def result = true        //evaluate something here to find the one
                    if(result)return tag[2]  //search done - return the value
                    else return null         //continue searching
                }
assert tagname=='refs/tags/annotated'

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。