Jenkins Pipeline使用findFiles获取子目录内容的问题求解
Jenkins Pipeline中findFiles枚举子目录文件异常解决方案
问题背景
当前Jenkins环境已安装pipeline-utility-steps插件,findFiles步骤在普通构建任务中可正常调用,但在Pipeline中枚举子目录文件时连续遇到异常,已尝试的写法及对应问题如下:
- 通配符递归写法
执行代码:
异常表现:进程持续挂起,无返回结果。def files = findFiles(glob: "dirname/**") - 切换工作目录写法
执行代码:
异常表现:执行失败,步骤会尝试创建dir("dirname") { def files = findFiles() }dirname@tmp目录,要求持有父目录写权限;放宽父目录权限后可正常运行,但出于安全要求,不能授予Jenkins服务账号该父目录的写权限。 - 脚本控制台测试
在Jenkins脚本控制台执行如下测试代码:
抛出异常:def files = findFiles() println(files)groovy.lang.MissingMethodException: No signature of method: Script1.findFiles() is applicable for argument types: () values: [] Possible solutions: findAll(), findAll(groovy.lang.Closure), find()
异常原因说明
- 脚本控制台调用报错属于预期行为:
findFiles是Pipeline专属步骤,不属于Jenkins Groovy沙箱内置方法,无法在Pipeline上下文外的脚本控制台直接调用,该报错不代表插件安装异常。 dir()块权限报错为步骤固有逻辑:dir()步骤切换到非当前工作空间下的目录时,默认会在目标目录同级创建目录名@tmp临时工作目录,该行为无配置项可关闭,因此只要对父目录无写权限,该写法必然失败。- 通配符
**写法挂起通常是递归死循环导致:无深度限制的**递归会遍历所有子节点,若目标目录下存在指向上层目录的软链接、挂载的超大容量存储目录,会触发无限递归或遍历超时,最终表现为进程挂起。
可用实现方案
方案1:限定通配符遍历深度,规避死循环
如果不需要无限制深度递归,可明确指定遍历层级,避免触发软链接死循环,该写法全程仅需目标目录读权限,不会创建临时文件:
// 遍历dirname下最多2层子目录的所有文件,可按需增减*/*层级调整深度 def files = findFiles(glob: "dirname/{*,*/*}") // 遍历3层的写法为 glob: "dirname/{*,*/*,*/*/*}"
方案2:调用原生文件API,绕开dir步骤逻辑
如果需要全量递归遍历,又不能授予父目录写权限,可直接使用Groovy原生文件API操作,完全不依赖dir()步骤,无临时目录创建逻辑:
// 拼接目标目录绝对路径,不需要切换工作目录 def targetPath = "${pwd()}/dirname" def targetDir = new File(targetPath) // 递归列出目录下所有文件,内置软链接死循环规避逻辑 def listFiles(File dir) { def result = [] dir.eachFile { file -> if (file.isFile()) { result << file.absolutePath } else if (file.isDirectory() && !file.canonicalPath.startsWith(dir.canonicalPath)) { // 跳过指向目录外的软链接,避免死循环 return } else if (file.isDirectory()) { result.addAll(listFiles(file)) } } return result } def files = listFiles(targetDir)
该方案仅要求Jenkins服务账号对目标dirname目录持有读权限,无额外权限要求。
方案3:全量递归时排除异常目录
如果必须使用findFiles的**全量递归逻辑,可通过excludes参数明确排除会导致死循环的软链接目录、大容量挂载目录:
def files = findFiles( glob: "dirname/**", excludes: "dirname/上层软链接名/**,dirname/大容量挂载目录名/**" )
内容的提问来源于stack exchange,提问作者carl verbiest
相关产品推荐
相关产品推荐

