如何使用JAVA调用SHELL
通过ProcessBuilder进行调度
这种方法比较直观,而且参数的设置也比较方便,比如我在实践中的代码(我隐藏了部分业务代码):
ProcessBuilderpb=newProcessBuilder("./"+RUNNING_SHELL_FILE,param1, param2,param3); pb.directory(newFile(SHELL_FILE_DIR)); intrunningStatus=0; Strings=null; try{ Processp=pb.start(); try{ runningStatus=p.waitFor(); }catch(InterruptedExceptione){ } }catch(IOExceptione){ } if(runningStatus!=0){ } return;
这里有必要解释一下几个参数:
RUNNING_SHELL_FILE:要运行的脚本
SHELL_FILE_DIR:要运行的脚本所在的目录;当然你也可以把要运行的脚本写成全路径。
runningStatus:运行状态,0标识正常。详细可以看java文档。
param1,param2,param3:可以在RUNNING_SHELL_FILE脚本中直接通过1,2,$3分别拿到的参数。
直接通过系统Runtime执行shell
这个方法比较暴力,也比较常用,代码如下:
p=Runtime.getRuntime().exec(SHELL_FILE_DIR+RUNNING_SHELL_FILE+""+param1+""+param2+""+param3); p.waitFor();
我们发现,通过Runtime的方式并没有builder那么方便,特别是参数方面,必须自己加空格分开,因为exec会把整个字符串作为shell运行。
可能存在的问题以及解决方法
如果你觉得通过上面就能满足你的需求,那么可能是要碰壁了。你会遇到以下情况。
没权限运行
这个情况我们团队的朱东方就遇到了,在做DTS迁移的过程中,要执行包里面的shell脚本,解压出来了之后,发现执行不了。那么就按照上面的方法授权吧
ProcessBuilderbuilder=newProcessBuilder("/bin/chmod","755",tempFile.getPath()); Processprocess=builder.start(); intrc=process.waitFor();
java进行一直等待shell返回
这个问题估计更加经常遇到。原因是,shell脚本中有echo或者print输出,导致缓冲区被用完了!为了避免这种情况,一定要把缓冲区读一下,好处就是,可以对shell的具体运行状态进行log出来。比如上面我的例子中我会变成:
ProcessBuilderpb=newProcessBuilder("./"+RUNNING_SHELL_FILE,keyword.trim(), taskId.toString(),fileName); pb.directory(newFile(CASPERJS_FILE_DIR)); intrunningStatus=0; Strings=null; try{ Processp=pb.start(); BufferedReaderstdInput=newBufferedReader(newInputStreamReader(p.getInputStream())); BufferedReaderstdError=newBufferedReader(newInputStreamReader(p.getErrorStream())); while((s=stdInput.readLine())!=null){ LOG.error(s); } while((s=stdError.readLine())!=null){ LOG.error(s); } try{ runningStatus=p.waitFor(); }catch(InterruptedExceptione){ }
记得在start()之后,waitFor()之前把缓冲区读出来打log,就可以看到你的shell为什么会没有按照预期运行。这个还有一个好处是,可以读shell里面输出的结果,方便java代码进一步操作。