Linux下ProcessBuilder执行sonar-scanner报error=2找不到文件问题
问题原因
你遇到的error=2, No such file or directory报错不是路径拼接错误导致的,Windows能正常运行、Linux下文件存在却启动失败,是四个Linux环境特有问题导致的:
sh -c调用方式错误。sh -c的语法要求后续所有待执行命令必须作为单个完整字符串传入,你当前代码把sonar-scanner和后续参数逐个加入命令列表,实际执行时sh只会识别第一个参数为执行命令,后续参数会被识别为sh本身的位置参数,不会传给sonar-scanner,直接导致命令解析失败。- 可执行权限缺失。Linux下文件存在但没有
+x执行权限时,Java的ProcessBuilder启动程序会抛出和“文件不存在”完全相同的报错,属于常见的误导性异常信息。 - 脚本解释器不匹配。官方sonar-scanner启动脚本的首行shebang默认是
#!/bin/bash,如果你的Linux运行环境是精简版(比如Alpine容器),默认没有安装bash、只有sh,哪怕脚本文件本身存在,也会因为找不到解释器抛出这个错误。 - 隐性路径问题:你当前传入的是相对路径
sonar-scanner,部分OpenJDK版本在Linux环境下不会优先从ProcessBuilder设置的工作目录检索可执行文件,也会触发找不到文件的报错。
修复步骤
- 先做环境前置校验
进入sonar-scanner所在的bin目录,执行以下命令:# 给启动脚本加全局可执行权限 chmod +x sonar-scanner # 检查脚本首行的解释器路径,如果输出#!/bin/bash但当前环境没有bash,要么安装bash,要么把首行改为#!/bin/sh head -n 1 sonar-scanner - 修正代码逻辑,去掉不必要的sh/cmd套壳调用,直接传入可执行文件的绝对路径,避免参数解析问题:
// 提前引入java.util.Arrays、java.io.File类 String jarPath = utility.findJarLocation(); ArrayList<String> commandList = new ArrayList<>(); // 用系统自带的文件分隔符拼接路径,避免跨平台兼容问题 String scannerBinDir = jarPath + File.separator + "sonarScanner" + File.separator + "bin"; if (parameters.getSistemaOperativo().equals("w")) { // Windows环境 commandList.add(scannerBinDir + File.separator + "sonar-scanner.bat"); } else { // Linux、Mac环境 String scannerExecPath = scannerBinDir + File.separator + "sonar-scanner"; File scannerFile = new File(scannerExecPath); // 代码层面主动设置可执行权限,避免手动配置遗漏 if (scannerFile.exists() && !scannerFile.canExecute()) { scannerFile.setExecutable(true, false); } commandList.add(scannerExecPath); } // 注意:如果参数包含带空格的带引号值,不要用简单空格拆分,会破坏参数结构 String[] scannerParams = parameters.getSonarScannerParameters().trim().split("\\s+"); commandList.addAll(Arrays.asList(scannerParams)); ProcessBuilder pb = new ProcessBuilder(commandList); pb.directory(new File(scannerBinDir)); pb.redirectErrorStream(true); Process pr = pb.start(); - 额外优化:如果后续遇到带空格的sonar参数(比如项目路径含空格、配置值含空格),建议替换简单的
split(" ")逻辑为正规的命令行参数分词逻辑,避免参数传递错误。
内容的提问来源于stack exchange,提问作者Andrea Chirigu
相关产品推荐
相关产品推荐

