java執(zhí)行shell并獲取shell輸出日志方式
java執(zhí)行shell并獲取shell輸出日志
獲取shell輸出日志需要java使用兩個線程分別接受shell的標準輸入流和錯誤流并打印出來
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class ShellLogRunTest {
public static void main(String[] args) throws Exception, SecurityException {
Process p = null;
Runtime rt = Runtime.getRuntime();
String command = "cmd /c java -version";
command = "cmd /c ping 127.0.0.1 -n 3";
if (args != null && args.length > 0 && args[0] != null && args[0].trim().length() > 0) {
command = args[0];
}
try {
p = rt.exec(command, null, null);
// 獲取進程的標準輸入流
final InputStream is1 = p.getInputStream();
// 獲取進城的錯誤流
final InputStream is2 = p.getErrorStream();
// 啟動兩個線程,一個線程負責讀標準輸出流,另一個負責讀標準錯誤流
new Thread() {
public void run() {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1, Charset.forName("gb2312"))); // 這里要注意shell返回的類型,windows和linux可能不同
try {
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
System.out.println(line1);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is1.close();
System.out.println("is1線程關閉");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
public void run() {
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2, Charset.forName("gb2312")));
try {
String line2 = null;
while ((line2 = br2.readLine()) != null) {
if (line2 != null) {
System.out.println(line2);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is2.close();
System.out.println("is2線程關閉");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
p.waitFor();
p.destroy();
System.out.println("進程結束");
} catch (Exception e) {
try {
p.getErrorStream().close();
p.getInputStream().close();
p.getOutputStream().close();
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
}
java執(zhí)行shell命令(分批 多條 走一步看一步的執(zhí)行)
說明
網上有很多通過java執(zhí)行命令的程序,但是只能執(zhí)行一條命令,或者是所有命令一次性執(zhí)行完畢。
而我想要的是執(zhí)行一條命令,看一看返回結果,然后在去執(zhí)行下一條命令,可惜翻遍全網,竟然一個可行的方法都沒有?。?!
沒辦法,自己想辦法解決吧。
實現代碼
廢話不多說,直接上代碼:
入口類
import core.CmdClient;
public class Main
{
public static void main(String[] args)
{
CmdClient client = new CmdClient();
client.run("cd /");
client.run("ls");
client.run("exit");
System.out.println("主線程結束");
}
}
核心代碼類:
這里就盡量不寫的太復雜,把多線程直接的交互都給砍掉了。大家可以根據自己需求去修改。
package core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class CmdClient
{
// 中文有亂碼的可以試著改一下編碼格式。
private static final Charset charset = StandardCharsets.UTF_8;
// 初始化
public CmdClient()
{
try
{
/*
Runtime.getRuntime().exec()方法本質和windows上的運行一樣,只能執(zhí)行一個命令來啟動一個程序。
這里啟動的是sh解釋器,可以根據需要改成其他shell解釋器。適用mac,linux系統(tǒng)。
對于windows,則是運行C:\Windows\System32\cmd.exe,同時執(zhí)行的也不是shell命令,而是dos命令。
*/
Process process = Runtime.getRuntime().exec("/bin/sh");
// 獲取程序的輸出流和輸入流
inputStream = process.getInputStream();
errorStream = process.getErrorStream();
outputStream = process.getOutputStream();
/*
輸出數據需要,若執(zhí)行的命令沒有輸出結果,就會阻塞讀取流的線程。
為了防止主線程被阻塞,所以聲明新的線程專門盯著輸出數據。
*/
new Thread(this::ReadCmdOut).start();
new Thread(this::ReadCmdError).start();
}
catch (IOException e)
{ throw new RuntimeException("cmd初始化異常", e); }
System.out.println("控制臺初始化完畢");
}
private final InputStream inputStream;
private final InputStream errorStream;
private final OutputStream outputStream;
// 運行命令
public void run(String cmd)
{
try
{
// 若執(zhí)行某些命令出現異常,可以嘗試更換 \n 為 \r 或 \n\r
outputStream.write((cmd + "\n").getBytes(charset));
outputStream.flush();
}
catch (Exception e)
{ throw new RuntimeException("命令執(zhí)行錯誤:" + cmd, e); }
}
private void ReadCmdOut()
{
try
{ print(inputStream); }
catch (Exception e)
{ throw new RuntimeException("獲取輸出流異常", e); }
System.out.println("正常輸出流結束");
}
private void ReadCmdError()
{
try
{ print(errorStream); }
catch (Exception e)
{ throw new RuntimeException("獲取錯誤流異常", e); }
System.out.println("異常輸出流結束");
}
/**
* 這里直接把數據打印出來了,有其他需求的可以在這里寫判來確定下一步來執(zhí)行什么。
*/
private void print(InputStream inputStream) throws IOException
{
byte[] bytes = new byte[1024];
int i;
while (true)
{
i = inputStream.read(bytes);
if (i == -1) break;
System.out.print(new String(bytes, 0, i, charset));
}
System.out.println();
}
}
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Spring MVC 文件、cookies的接收 與REST響應詳
在SpringMVC中,使用@RequestPart注解可接收文件并處理多部分請求,同時可以通過@CookieValue和HttpServletResponse來獲取和設置Cookies,本文介紹Spring MVC 文件、cookies的接收 與REST響應,感興趣的朋友跟隨小編一起看看吧2024-09-09
Spring?Security中如何獲取AuthenticationManager對象
有時需要使用AuthenticationManager(以下簡稱Manager)對象,可是這個對象不是Bean,沒有直接保存在Spring的Bean庫中,那么如何獲取Spring Security中的這個對象呢,需要的朋友可以參考下2022-11-11
SpringMVC使用@ExceptionHandler注解在Controller中處理異常
這篇文章主要為大家介紹了SpringMVC使用@ExceptionHandler注解在Controller中處理異常示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10
SpringBoot+MyBatis報錯:Invalid bean definition的原因排查與
這篇文章主要為大家詳細介紹了SpringBoot+MyBatis報錯:Invalid bean definition的原因排查與解決方法,文中的示例代碼講解詳細,希望對大家有所幫助2025-09-09

