从 groovy 脚本调用的外部进程处理多行输出的最佳方法?
Best way to work on multi-line output from external process called from groovy script?
我用这个方法:
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()
}
到 运行 可以 return 一行或多行输出的外部进程。
有时我需要检查每一行,如果找到则 return 匹配。首先,我尝试使用 eachLine
闭包,但发现我无法从 (Can you break from a Groovy "each" closure?):
return
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
}
}
}
}
这很漂亮 verbose/ugly 并且当 tagsArr
为 empty 时 not 是否工作(仍在调查这个和感谢任何输入!)。
关于如何更好地处理调用外部进程的多行输出有什么建议吗?
还有上面的这个:
return output.toString().split()
好像不太对...
我也看过:
http://konstructcomputers.blogspot.com/2013/12/groovy-line-by-line-process-output.html
看起来相当verbose/extensive。我希望 groovy 提供一些最小的方法来避免这种“低级”样板代码。
旁注。有趣的是这个页面:
http://docs.groovy-lang.org/latest/html/documentation/working-with-io.html
没有提到 waitForProcessOutput
我认为这是从外部进程获取输出的最可靠方法。
更新示例(使用 readLines 和查找)
下面是一个基于以下建议的更新示例。我修改了原始示例以使其更清楚。
预期结果=注释
$ 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 = 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 NO split()
return output
}
def sample() {
def tags = runProcess(["git", "tag","--points-at","HEAD"])
def result = tags.readLines().find{ tag ->
def tagType = runProcess(["git", "cat-file","-t","$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'
我用这个方法:
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()
}
到 运行 可以 return 一行或多行输出的外部进程。
有时我需要检查每一行,如果找到则 return 匹配。首先,我尝试使用 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
}
}
}
}
这很漂亮 verbose/ugly 并且当 tagsArr
为 empty 时 not 是否工作(仍在调查这个和感谢任何输入!)。
关于如何更好地处理调用外部进程的多行输出有什么建议吗?
还有上面的这个:
return output.toString().split()
好像不太对...
我也看过:
http://konstructcomputers.blogspot.com/2013/12/groovy-line-by-line-process-output.html
看起来相当verbose/extensive。我希望 groovy 提供一些最小的方法来避免这种“低级”样板代码。
旁注。有趣的是这个页面:
http://docs.groovy-lang.org/latest/html/documentation/working-with-io.html
没有提到 waitForProcessOutput
我认为这是从外部进程获取输出的最可靠方法。
更新示例(使用 readLines 和查找)
下面是一个基于以下建议的更新示例。我修改了原始示例以使其更清楚。
预期结果=注释
$ 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 = 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 NO split()
return output
}
def sample() {
def tags = runProcess(["git", "tag","--points-at","HEAD"])
def result = tags.readLines().find{ tag ->
def tagType = runProcess(["git", "cat-file","-t","$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'