Jenkins Pipeline运行Python脚本取最后令牌,避免重复执行且显示日志
问题
我原本用这段Jenkins Pipeline代码运行Python脚本,还能拿到输出的最后一个令牌:
A = bat(script:'c:\python27\python.exe D:\A.py', returnStdout: true).tokenize().last
这段代码能正常跑,但我想同时看到Python脚本的日志,就改成了下面这样:
A = bat(script:'c:\python27\python.exe D:\A.py', returnStdout: true).tokenize() B = A.last println A
结果坑来了——Python脚本被执行了两次!这完全不是我想要的,有没有办法解决?
解决建议
哈哈,这个坑我之前也踩过!问题出在Jenkins Pipeline的惰性求值机制上:bat这类步骤返回的不是普通字符串,而是一个特殊的对象,每次你去访问它的内容(比如调用tokenize()或者直接打印),它就会重新执行一遍对应的命令。你修改后的代码相当于触发了两次bat的执行逻辑,所以脚本跑了两次。
给你几个靠谱的解决办法:
1. 先把输出存到变量,再处理
最稳妥的方式就是先把bat的输出完整存到一个普通变量里,之后再对这个变量做分词、取最后元素等操作,这样bat只会执行一次:
// 先把脚本的完整输出存下来,只执行一次bat def fullOutput = bat(script:'c:\\python27\\python.exe D:\\A.py', returnStdout: true).trim() // 再对保存好的输出做处理 def tokenList = fullOutput.tokenize() def lastToken = tokenList.last() // 打印分词后的列表和原始输出(这样就能看到日志了) println "分词结果:${tokenList}" println "脚本原始输出:${fullOutput}"
另外提醒一下:Groovy里字符串的反斜杠要转义,所以路径里的\要写成\\,不然会被解析成特殊字符,导致路径出错哦。
2. 让日志直接输出到Jenkins控制台
如果你想让Python脚本的日志直接显示在Jenkins的构建日志里(不用手动打印原始输出),可以用stdout参数捕获输出,同时把returnStdout设为false:
def fullOutput = bat( script:'c:\\python27\\python.exe D:\\A.py', returnStdout: false, // 让日志直接输出到控制台 stdout: true // 同时捕获输出内容 ).stdout.trim() // 后续处理和上面一样 def tokenList = fullOutput.tokenize() def lastToken = tokenList.last() println "最后一个令牌:${lastToken}"
这种方式下,Python脚本的所有日志会直接出现在Jenkins的构建记录里,你还能拿到输出内容做后续处理,一举两得。
为什么原来的代码只执行一次?
因为原来的代码是链式调用:bat(...).tokenize().last——整个操作只触发了一次对bat返回对象的访问,所以只会执行一次脚本。而修改后,由于你拆分了操作步骤,间接触发了多次对特殊对象的访问,才导致重复执行。
内容的提问来源于stack exchange,提问作者Yu Zou




