调用java.lang.Runtime.exec的正确姿势
今天写一个用到编译的程序,遇到了问题。
在调用
1
|
runtime.exec( "javac HelloWorld.java" ); |
运行完美,也就是有生成.class。
而到了
1
|
runtime.exec( "java HelloWorld >> output.txt" ); |
却怎么也无法重定向输出,连output.txt文件也生成不了。
测试"echo hello >> 1.txt" 也是不可以,甚是头疼,于是乎翻阅资料,这才发现了
一个认识上的误区,就是exec(str)中 不能把str完全看作命令行执行的command。尤其是str中不可包含重定向 ' < ' ' > ' 和管道符' | ' 。
那么,遇到这样的指令怎么办呢?我们接着往下看:
两种方法
一种是将指令写到脚本中,在runtime.exec()中调用脚本。这种方法避过了使用exec(),也是一种思路。
还有一种方法,就是调用exec()的重载方法:我们来重点看这种方法:
我们先看一下官方doc[>link<]给我们提供的重载方法:
1
2
3
4
5
6
|
public Process exec(String command) throws IOExecption public Process exec(String command,String [] envp) throws IOExecption public Process exec(String command,String [] envp,File dir) throws IOExecption public Process exec(String[] cmdarray) throws IOExecption public Process exec(String[] cmdarray,String [] envp) throws IOExecption public Process exec(String[] cmdarray,String [] envp,File dir) throws IOExecption |
翻阅其文档,发现其重载方法4.exec(String []cmdarray) 最简便适合我们,官方说4.exec() 与执行6.exec(cmdarray,null,null) 效果是一样的。那么5.exec.(cmdarray,null)也是一样的咯?
于是乎,我们可以这样写:
1
2
3
|
runtime.exec( new String[]{ "/bin/bash" , "-c" , "java HelloWorld >> output.txt" } ); runtime.exec( new String[]{ "/bin/bash" , "-c" , "java HelloWorld >> output.txt" } , null ); runtime.exec( new String[]{ "/bin/bash" , "-c" , "java HelloWorld >> output.txt" } , null , null ); |
不过要注意,如果使用java /home/path/HelloWorld 时,' / '会被解析成 " . ",从而报出 “错误: 找不到或无法加载主类 .home.path.HelloWorld ”.
所以,无法使用全路径的时候,我们需要更改一下策略,把 路径 改到工作目录dir 中去,比如:
1
|
File dir = new File( "/home/path/" ); |
然后用其第6种重载方法,把dir作为第三个参数传入即可:
1
2
|
String []cmdarry ={ "/bin/bash" , "-c" , "java HelloWorld >> output.txt" } runtime.exec(cmdarry, null .dir); |
当然echo , ls 等命令便不受' / '限制了。
*BTW,exec()取得返回值的标准用法详见:runtime.exec()的左膀右臂
小结一下
当命令中包含重定向 ' < ' ' > ' 和管道符' | ' 时,exec(String command)方法便不适用了,需要使用exec(String [] cmdArray) 或者exec(String []cmdarray,String []envp,File dir)来执行。
例如:
1
2
|
exec( "echo hello >> ouput.txt" ); exec( "history | grep -i mvn" ); |
应改为:
1
2
|
exec( new String[]{ "/bin/sh" , "-c" , "echo hello >> ouput.txt" }); exec( new String[]{ "/bin/bash" , "-c" , "history | grep -i mvn" }, null ); |
Java Runtime.exec()注意事项
-
Runtime.exec()
用来执行外部程序或命令
1.Runtime.exec() 有四种调用方法
1
2
3
4
|
* public Process exec(String command); * public Process exec(String [] cmdArray); * public Process exec(String command, String [] envp); * public Process exec(String [] cmdArray, String [] envp); |
2.得到程序执行返回值, 0为success
需要用waitFor()函数,比如
1
2
3
|
Process p = Runtime.getRuntime().exec( "javac" ); (处理.....) int exitVal = p.waitFor(); |
3.得到程序执行的结果或错误信息
需要用BufferedInputStream 和 BufferReader来得到,否则程序会hang
比如得到错误信息用p.getErrorStream(),然后输出即可:
1
2
|
BufferedInputStream in = new BufferedInputStream(p.getErrorStream()); BufferedReader br = new BufferedReader( new InputStreamReader(in)); |
4.Runtime.exec()
不等同于直接执行command line命令
啊,我算是在这里吃了苦头了。Runtime.exec()很有局限性,对有些命令不能直接把command line里的内容当作String参数传给exec().
比如重定向等命令。举个例子:
1
|
javap -l xxx > output.txt |
这时要用到exec的第二种重载,即input 参数为String[]:
1
|
Process p = Runtime.getRuntime().exec( new String[]{ "/bin/sh" , "-c" , "javap -l xxx > output.txt" }); |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/timo1160139211/article/details/75006938