scala/java 通过bash创建新的进程,杀死相应进程
2019-02-25
我们经常可能需要从代码中启动一个脚本,或者一个程序来辅助自己完成需要的功能。比如bash脚本启动一个程序服务,可以通过进程之间的通信(比如socket)获取本程序想要的信息。
##进程的创建
Java提供了两种方法用来启动进程或其它程序:
(1)使用Runtime的exec()方法
(2)使用ProcessBuilder的start()方法
实际上Runtime.exec() 代码中最终也调用了ProcessBuilder的start()方法 。
这里主要展示一个简单的执行查看网卡信息的代码和从java代码中启动一个bash进程执行java命令的代码
// bash查看网络配置信息
String cmd = "ifconfig";
String [] execCmd = {"sh", "-c", cmd};
Process process = Runtime.getRuntime().exec(execCmd);
process.waitFor();
Scanner scanner = new Scanner(process.getInputStream());
while(scanner.hasNextLine()){
System.out.println(scanner.nextLine());
}catch (Exception ex){
ex.printStackTrace();
// bash执行java的main函数
String classpath = System.getProperty("java.class.path");
// -cp -> -classpath, 这里是前提是代码已经编译成class文件,且在infrastructure包下有一个包含main函数的TranswarpServer类,且这个main函数可以接受三个String的参数12346 server1 NORMAL
String cmd = "java -cp " + classpath + " infrastructure.TranswarpServer 12346 server1 NORMAL";
// String cmd = "nohup java -cp " + classpath + " infrastructure.TranswarpServer 12346 server1 NORMAL &"; //如果不想因为等待这个进程完成而堵塞,可以直接选择在bash里挂起进程
String [] env = {"PATH=%s:%s/bin".format(System.getenv("PATH"),System.getenv("JAVA_HOME"))};
String [] execCmd = {"sh", "-c", cmd};
Process process = Runtime.getRuntime().exec(execCmd, env);
process.waitFor();
Scanner scanner = new Scanner(process.getInputStream());
// Scanner scanner = new Scanner(process.getErrorStream()); //可以查看java不能正常执行的报错信息
while(scanner.hasNextLine()){
System.out.println(scanner.nextLine());
// Thread.sleep(1000);
}catch (Exception ex){
ex.printStackTrace();
代码中启动的新进程可能是一个服务或者类似ping baidu.com这种的不停执行的命令,不会因为当前进程的退出而退出。而且进程process对象中也无法获取到进程的id,给我们用于kill。
杀掉创建的进程
代码中通过启动一个新的进程找到和之前启动的进程相关的程序,比如之前启动的进程包含了执行infrastructure.TranswarpServer的java程序,那么可以通过ps aux | grep ‘infrastructure.TranswarpServer’找到相关的进程信息
我们简单测试就可知,从代码中执行ps aux | grep ‘infrastructure.TranswarpServer’指令,得到的不止我们需要的信息,还包括grep本身的进程,以及我们bash -c启动的进程信息,如下所示的这前两个就是无用的,最后一个才是我们真正需要的,而且这个bash执行完,前两个进程实际就消失了。
但是我们不用在意这些,将所有的pid都收集起来形成一个list,均kill -9 掉,如果已经不存在,kill -9 也不会有什么作用,对真正我们要kill的pid,也能正常kill。
ganjun 11178 0.0 0.0 2432804 1324 ?? R 6:47PM 0:00.00 grep infrastructure.TranswarpServer
ganjun 11176 0.0 0.0 2435440 2124 ?? S 6:47PM 0:00.00 bash -c ps aux | grep 'infrastructure.TranswarpServer'
ganjun 10014 0.0 0.2 8207960 29408 ?? S 6:15PM 0:02.33 /usr/bin/java -cp ... infrastructure.TranswarpServer
def getProcessIds(key: String): util.ArrayList[Int] ={
import java.io.{BufferedReader, InputStreamReader}
var pids = new util.ArrayList[Int]()
val re = false
val command = s"ps aux | grep '${key}'"
val process = Runtime.getRuntime.exec( Array("bash", "-c", command) )
val br = new BufferedReader(new InputStreamReader(process.getInputStream))
var line: String = br.readLine()
while (line != null){
println(line)
val tInputStringStream = new ByteArrayInputStream(line.getBytes)
// let string as input stream read the process id
val scanner = new Scanner(tInputStringStream)
val user = scanner.next()
val pid = scanner.nextInt()
scanner.close()
pids.add(pid)
line = br.readLine()
br.close()
} catch {
case e: Exception =>
System.out.println(e.toString)
// 统计实际删除的进程个数
def killProcesses(key: String): Int={
var killNumbers = 0
val pids: List[Int] = getProcessIds(key)
println( pids )
pids.foreach(pid => {
val process = Runtime.getRuntime().exec(Array("bash", "-c", s"kill -9 ${pid}"))
if( process.waitFor() == 0) // 因为有些得到的进程id是前面本身grep产生的无意义的
killNumbers += 1
killNumbers
killProcesses("infrastructure.TranswarpServer")