Java调⽤Shell命令和脚本-Runtime⽅式
Java调⽤Shell命令和脚本-Runtime⽅式
使⽤java调⽤命令⾏在项⽬的开发中经常会使⽤到,在我最近的⼀个项⽬中,也使⽤到了java调⽤命令和shell脚本。我将⽤这篇⽂章记录下来java调⽤命令⾏的实现。
这个是java中使⽤最多的⼀种⽅案吧,对于Runtime在JAVA的API中是这样解释的:
每个 Java 应⽤程序都有⼀个 Runtime 类实例,使应⽤程序能够与其运⾏的环境相连接。可以通过 getRuntime ⽅法获取当前运⾏时。
应⽤程序不能创建⾃⼰的 Runtime 类实例。
从这个API中可以得到⼀个⾮常重要的信息,那就是应⽤程序与其运⾏的环境相连接。也就是说在执⾏命令⾏时,相关的⼀些运⾏环境已经帮你设置好了,直接执⾏命令或者脚本即可。
再来看下具体执⾏的相关⽅法的API。
返回类型⽅法及参数
Process exec(String command) 在单独的进程中执⾏指定的字符串命令。
Process exec(String[] cmdarray) 在单独的进程中执⾏指定命令和变量。
Process exec(String[] cmdarray, String[] envp) 在指定环境的独⽴进程中执⾏指定命令和变量。
Process exec(String[] cmdarray, String[] envp, File dir) 在指定环境和⼯作⽬录的独⽴进程中执⾏指定的命令和变量。
Process exec(String command, String[] envp) 在指定环境的单独进程中执⾏指定的字符串命令。
Process exec(String command, String[] envp, File dir) 在有指定环境和⼯作⽬录的独⽴进程中执⾏指定的字符串命令。
通过观察这些API发现这些API使⽤都⽐较简单,只需要根据⾃⼰的需要调⽤适合的参数即可。再来看看返回对象吧。
Process对象的API解释:
ProcessBuilder.start() 和 ⽅法创建⼀个本机进程,并返回 Process ⼦类的⼀个实例,该
实例可⽤来控制进程并获得相关信息。Process 类提供了执⾏从进程输⼊、执⾏输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的⽅法。
创建进程的⽅法可能⽆法针对某些本机平台上的特定进程很好地⼯作,⽐如,本机窗⼝进程,守护进程,Microsoft Windows 上的Win16/DOS 进程,或者 shell 脚本。创建的⼦进程没有⾃⼰的终端或控制台。它的所有标准 io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到⽗进程。⽗进程使⽤这些流来提供到⼦进程的输⼊和获得从⼦进程的输出。因为有些本机平台仅针对标准输⼊和输出流提供有限的缓冲区⼤⼩,如果读写⼦进程的输出流或输⼊流迅速出现失败,则可能导致⼦进程阻塞,甚⾄产⽣死锁。
当没有 Process 对象的更多引⽤时,不是删掉⼦进程,⽽是继续异步执⾏⼦进程。
对于带有 Process 对象的 Java 进程,没有必要异步或并发执⾏由 Process 对象表⽰的进程。
再来看下对象的信息
返回信息⽅法及参数
abstract void destroy() 杀掉⼦进程。
abstract int exitValue() 返回⼦进程的出⼝值。
abstract InputStream getErrorStream() 获取⼦进程的错误流。
abstract InputStream getInputStream() 获取⼦进程的输⼊流。
abstract OutputStream getOutputStream() 获取⼦进程的输出流。
abstract int waitFor() 导致当前线程等待,如有必要,⼀直要等到由该 Process 对象表⽰的进程已经终⽌。
在这个返回值的API中,有两个⽅法需要特别注意下,exitValue()和waitFor()⽅法
exitValue()⽅法如果⼦进程未终⽌,则抛出⼀个IllegalThreadStateException 异常,如果⼦进程终⽌,则返回⼀个退出值。
waitFor()⽅法将阻塞调⽤线程,直到⼦进程终⽌,如果⼦进程已经终⽌则⽴即返回。
因此当⼦进程已经终⽌时,他们的⾏为将是相同的,当⼦进程在运⾏时,他们的⾏为将有所不同。exitValue将抛出异常,⽽waitFor则阻塞调⽤线程。
1. 代码实现
好了,接下来就是代码环节了:
public class SynchronousLocalShellCommand {
private Logger logger = Logger(SynchronousLocalShellCommand.class);
/** 命令信息 */
private final String command;
public SynchronousLocalShellCommand(String command){
thismand = command;
}
/**
* 执⾏命令并返回结果
*
* @return 命令执⾏结果
*/
public String doCommand(){
// 获取操作流
Process process = null;
String errorMsg = null;
try{
process = Runtime().exec(command);
}catch(IOException e){
<("command : {} ,exception", command, e);
errorMsg = e.getMessage();
}
// 当对象获取不成功时,返回对象
if(null == process){
return errorMsg;
}
// 获取⼦进程的输⼊流。输⼊流获得由该 Process 对象表⽰的进程的标准输出流。
String commandRspOk =InputStream());
// 进⾏错误信息的读取操作
String commandRspError =ErrorStream());
String commandRspError =ErrorStream());
// 构建响应结果
String commandRsp = commandRspOk + Symbol.LINE + Symbol.LINE + commandRspError;
int rsp =-1;
try{
// 等待进程结束。
rsp = process.waitFor();
}catch(InterruptedException e){
<("run command {} InterruptedException", command, rsp);
}
logger.info("run command {}, response {}", command, rsp);
return commandRsp;
}
/
**
* 数据读取操作
*
* @param input 输⼊流shell脚本返回执行结果
*/
private String reader(InputStream input){
StringBuilder outDat =new StringBuilder();
try(InputStreamReader inputReader =new InputStreamReader(input, StandardCharsets.UTF_8); BufferedReader bufferedReader =new BufferedReader(inputReader)){
String line;
while((line = adLine())!= null){
outDat.append(line);
outDat.append(Symbol.LINE);
}
}catch(IOException e){
<("command : {} ,exception", command, e);
}
String();
}
}
1.1 环境测试-linux
然后我们将在linux系统上做⼀个测试。下⾯是⼀段测试代码
public class RuntimeLinuxMain {
public static void main(String[] args){
RuntimeLinuxMain instance =new RuntimeLinuxMain();
// 同步的执⾏
instance.synchornousDoCommand();
}
/** 同步执⾏命令 */
private void synchornousDoCommand(){
//执⾏⼀个ping命令,将在5次后返回
this.runSyncCommand("ping -c 5 www.baidu");
//执⾏⼀个shell脚本
this.runSyncCommand("/home/liujun/datarun/shell/run.sh");
/
/执⾏⼀个错误的命令,不存在的
this.runSyncCommand("adfadsfa");
}
/**
* 执⾏同步的命令操作
*
* @param commandStr
*/
private void runSyncCommand(String commandStr){
SynchronousLocalShellCommand command =new SynchronousLocalShellCommand(commandStr); String commandRsp = command.doCommand();
System.out.println("同步执⾏结果:"+ commandRsp);
System.out.println("结束---------------");
}
}
以下是测试的⼀个shell脚本的内容:
#!/bin/bash
echo"Hello World !"
运⾏结果
[liujun@fk03 datarun]$ java -cp demojava8-0.0.1-SNAPSHOT.jar:./lib/* com.liujunmand.RuntimeLinuxMain
12:29:14.348 [main] INFO com.liujunmand.runtime.SynchronousLocalShellCommand - run command ping -c 5 www.baidu, response 0
同步执⾏结果:PING www.a.shifen (180.101.49.11) 56(84) bytes of data.
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=1 ttl=52 time=9.94 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=2 ttl=52 time=9.81 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=3 ttl=52 time=9.19 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=4 ttl=52 time=8.95 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=5 ttl=52 time=9.00 ms
--- www.a.shifen ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 8.953/9.382/9.948/0.426 ms
结束---------------
12:29:14.359 [main] INFO com.liujunmand.runtime.SynchronousLocalShellCommand - run command /home/liujun/datarun/shell/run.sh, response 0同步执⾏结果:Hello World !
结束---------------
12:29:14.363 [main] ERROR com.liujunmand.runtime.SynchronousLocalShellCommand - command: adfadsfa ,exception
java.io.IOException: Cannot run program "adfadsfa": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at java.(Runtime.java:620)
at java.(Runtime.java:450)
at java.(Runtime.java:347)
at com.liujunmand.runtime.SynchronousLocalShellCommand.doCommand(SynchronousLocalShellCommand.java:44)
at com.liujunmand.RuntimeLinuxMain.runSyncCommand(RuntimeLinuxMain.java:91)
at com.liujunmand.RuntimeLinuxMain.synchornousDoCommand(RuntimeLinuxMain.java:81)
at com.liujunmand.RuntimeLinuxMain.main(RuntimeLinuxMain.java:23)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 7 common frames omitted
同步执⾏结果:Cannot run program "adfadsfa": error=2, No such file or directory
结束---------------
[liujun@fk03 datarun]$
现在来分析下执⾏结果:
ping -c 5 www.baidu
可以看到这条命令的结果是成功的执⾏了!并且拿到了结果:
PING www.a.shifen (180.101.49.11) 56(84) bytes of data.
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=1 ttl=52 time=9.94 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=2 ttl=52 time=9.81 ms
64 bytes from 180.101.49.11 (180.101.49.11): icmp_seq=3 ttl=52 time=9.19 ms
第⼆条命令是执⾏⼀个shell脚本⽂件
/home/liujun/datarun/shell/run.sh
这个执⾏同样成功了,也拿到了输出的结果:
Hello World !
再说最后⼀个错误的命执⾏吧。
adfadsfa
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论