今天使用java调用linux命令出现了bug,有开始执行命令的日志打印,但是没有后续的执行结果打印,也没有错误日志出现。结果验证后发现命令还是没有执行成功,于是开始排查问题。以下是java代码:

System.out.println("got cmd job : " + cmd);
try {
// String[] cmds = new String[] {
// "/bin/sh",
// "-c",
// cmd };
Process process = Runtime.getRuntime().exec(cmd);
InputStream in ;
BufferedReader br;
in = process.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
while (in.read() != -1) {
result = br.readLine();
log.info("job result [" + result + "]");
}
br.close();
in.close();
//process.waitFor();
process.destroy();
} catch (Throwable e) {
log.error("执行linux命令出错:" + e.getMessage());
e.printStackTrace();
}

首先这段代码在测试环境中可以正常执行,也有执行结果的日志打印,由此可以排除掉是代码的问题。然后验证是否是linux命令写错,将命令放在Linux上运行,成功,排除是命令的问题。

考虑到使用java执行linux命令是单个事务执行,无法一步一步地执行命令,虽然这里使用了命令链接符&&,但为了避免这个问题,编写一个简单shell脚本,然后使用java执行。

以下是脚本:

#!/bin/sh
cd /root/git/mall.masadora.admin/dest
git pull
rm -rf /usr/server/java/tomcat_self_mall/webapps/ROOT/WEB-INF/dest
cp -rf /root/git/mall.masadora.admin/dest /usr/server/java/tomcat_self_mall/webapps/ROOT/WEB-INF

问题依然存在,结果还是和开始一样,回到最初。先考虑为什么没有错误日志打印,在代码中已经使用trycatch进行捕捉了,怀疑是java系统error异常,将 catch中的Exception改为Throwable,仍然没有发现错误日志打印。

没有办法了只能一行代码一行代码进行排查,第一步执行linux命令是java系统类runtime提供的方法,这个没什么好说的不会出问题。然后第二行,这里有一个Process类是执行linux命令后的结果,然后发现它内部除了有getInputStream方法外,还有一个getErrorStream方法,就是它了,修改代码,将errorStream中的内容打印出来,发现错误日志是git:command not found,由此可知是java执行shell脚本时没有获取到执行git命令的权限,在shell脚本上添加这些代码

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/git/bin:/usr/local/sbin:~/bin

export PATH

export LANG=en_US.UTF-8

执行成功。

总结:这次bug只是一个非常简单的问题,但是没有根据异常一步步回溯,而是靠猜测去各种尝试,这样做即浪费了时间,也无法在解决问题后了解整个bug的出现过程和原因,以后要避免这样