如何解决从 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 举报,一经查实,本站将立刻删除。