如何利用java过程执行操作系统命令

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何利用java过程执行操作系统命令相关的知识,希望对你有一定的参考价值。

参考技术A import java.io.InputStream;
import java.util.ArrayList;

public class JavaExcCommand
private static String INPUT_STREAM = "INPUTSTREAM";
private static String ERROR_STREAM = "ERRORSTREAM";

/**
* 返回命令执行结果信息串
* @param command 要执行的命令
* @return 第一个为标准信息,第二个为错误信息,如果不存在则相应为空
* @throws Throwable String[]
*/
public static String[] exec(String command) throws Throwable

Process process = null;
Runtime runtime = Runtime.getRuntime();

String osName = System.getProperty("os.name").toLowerCase();
if (osName.indexOf("windows 9") > -1)
process = runtime.exec("command.com /c " + command);
else if ((osName.indexOf("nt") > -1)
|| (osName.indexOf("windows 20") > -1)
|| (osName.indexOf("windows xp") > -1 || (osName.indexOf("windows vista") > -1)))

/*
* 开关/C指明后面跟随的字符串是命令,并在执行命令后关闭DOS窗口,使用cmd /?查看帮助
*/
process = runtime.exec("cmd.exe /c " + command);
else
// Linux,Unix
process = runtime.exec(command);


//存储返回结果,第一个为标准信息,第二个为错误信息
String result[] = new String[2];

Object mutexInstream = new Object();
Object mutexErrorstream = new Object();
new ReadThread(process.getInputStream(), INPUT_STREAM, result, mutexInstream)
.start();
new ReadThread(process.getErrorStream(), ERROR_STREAM, result, mutexErrorstream)
.start();
//确保子线程已启动
Thread.sleep(20);

/*
* 这里一定要等标准流与错误都读完了后才能继续执行后面的代码,否则外面引用返回的结果可能
* 为null或空串,所以要等两个线程执行完,这里确保读取的结果已返回。在读取时使用了两个线
* 程,因为发现在一个线程里读这种流时,有时会阻塞,比如代码实现时先读取标准流,而运行时
* 命令却执行失败,这时读标准流的动作会阻塞,导致程序最终挂起,先读错误流时如果执行时成
* 功,这时又可能挂起。还有一个问题就是即使使用两个线程分别读取流,如果不使用同步锁时,也
* 会有问题:主线程读不到子线程返回的数据,这主要是由于主线读取时子线还没未返回读取到的信
* 息,又因为两个读线程不能互斥,但又要与主线程同步,所以使用了两个同步锁,这样两个线程谁
* 先执行互不影响,而且主线程阻塞直到标准信息与错误信息都返回为止
*/
synchronized (mutexInstream)
synchronized (mutexErrorstream)
/*
* 导致当前线程等待,如果必要,一直要等到由该 Process 对象表示的进程已经终止
* 。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被
* 阻塞,直到退出子进程。
* process.waitFor()目的是等待子进程完成后再往下执行,不过这里好像没有什么
* 太大的作用除了用来判断返回的状态码外,因为如果程序进到这里表示子线程已执行完
* 毕,process子进程理所当然的也已执行完毕,如果子进程process未执行完,我想
* 读流的操作肯定会阻塞的。
*
* 另外,使用process.waitFor()要注的是一定不要在数据流读取前使用,否则线程
* 也会挂起,导致该现象的原因可能是该命令的输内容出比较多,而运行窗口的输出缓冲
* 区不够大,最后没不能写缓冲引起,所以这里先使用了两个单独的线程去读,这样不管
* 数据量有多大,都不会阻塞了。
*/
if (process.waitFor() != 0)
result[0] = null;
else
result[1] = null;



return result;


public static void main(String args[]) throws Throwable
if (args.length == 0)
System.out.println("Useage: \r\n java JavaExcCommand <command>");
return;

String[] result = JavaExcCommand.exec(args[0]);
System.out.println("error info:---------------\r\n" + result[1]);
System.out.println("std info:-----------------\r\n" + result[0]);


/*
* 标准流与错误流读取线程
*/
private static class ReadThread extends Thread
private InputStream is;
private String[] resultArr;
private String type;
private Object mutex;

public ReadThread(InputStream is, String type, String[] resultArr, Object mutex)
this.is = is;
this.type = type;
this.resultArr = resultArr;
this.mutex = mutex;


public void run()
synchronized (mutex)
try
int readInt = is.read();
ArrayList result = new ArrayList();

/*
* 这里读取时我们不要使用字符流与缓冲流,发现执行某些命令时会阻塞,不
* 知道是什么原因。所有这里使用了最原始的流来操作,就不会出现问题。
*/
while (readInt != -1)
result.add(Byte.valueOf(String.valueOf((byte) readInt)));
readInt = is.read();


byte[] byteArr = new byte[result.size()];
for (int i = 0; i < result.size(); i++)
byteArr[i] = ((Byte) result.get(i)).byteValue();

if (ERROR_STREAM.equals(this.type))
resultArr[1] = new String(byteArr);
else
resultArr[0] = new String(byteArr);


catch (Exception e)
e.printStackTrace();






比如传递一个参数为 dir/w ,运行结果如下:

error info:---------------
null
std info:-----------------
驱动器 E 中的卷是 Work
卷的序列号是 9876-AE7E

E:\_\Test 的目录

[.] [..] .classpath .project [bin] [lib]
[src]
2 个文件 904 字节
5 个目录 5,636,612,096 可用字节

如果传一个不存在的命令 aaa ,结果如下:

error info:---------------
'aaa' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

std info:-----------------
null

最后来一个查看操作系统的环境变量,注,这里不是使用的System.getXX来获取的,这是Java虚拟机设置的,我们这里是操作系统所设环境变量,如在window上输出 set ,或在 Linux 上输入 env ,window上运行的结果如下:

error info:---------------
null
std info:-----------------
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\jiangzhengjun\AppData\Roaming
classpath=D:\java\jdk1.5.0_17/lib;.
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=JZJ-PC
ComSpec=C:\Windows\system32\cmd.exe
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\jiangzhengjun
java_home=D:\java\jdk1.5.0_17
LOCALAPPDATA=C:\Users\jiangzhengjun\AppData\Local
LOGONSERVER=\\JZJ-PC
NUMBER_OF_PROCESSORS=2
OS=Windows_NT
Path=D:\java\jdk1.5.0_17/bin\..\jre\bin\client;D:\java\jdk1.5.0_17/bin\..\jre\bin;D:\java\jdk1.5.0_17/bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program Files\Broadcom\Broadcom 802.11\Driver
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 23 Stepping 6, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=1706
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\JIANGZ~1\AppData\Local\Temp
TMP=C:\Users\JIANGZ~1\AppData\Local\Temp
USERDOMAIN=jzj-pc
USERNAME=jiangzhengjun
USERPROFILE=C:\Users\jiangzhengjun
windir=C:\Windows

今天作项目时发现了一个简洁一点的办法:
Java代码
import java.io.InputStream;
import java.util.ArrayList;

public class JavaExcCommand

/**
* 返回命令执行结果信息串
*
* @param command
* 要执行的命令
* @return 第一个为标准信息,第二个为错误信息
* @throws Throwable
* String[]
*/
public static String[] exec(String command) throws Throwable
Process process = null;
Runtime runtime = Runtime.getRuntime();

// Linux,Unix
process = runtime.exec(command);

// 存储返回结果,第一个为标准信息,第二个为错误信息
String result[] = new String[2];
ReadThread inputReadThread = new ReadThread(process.getInputStream());
ReadThread errReadThread = new ReadThread(process.getErrorStream());
inputReadThread.start();
errReadThread.start();

//确保标准与错误流都读完时才向外界返回执行结果
while (true)
if (inputReadThread.flag && errReadThread.flag)
break;
else
Thread.sleep(1000);


result[0] = inputReadThread.getResult();
result[1] = errReadThread.getResult();
return result;


public static void main(String args[]) throws Throwable
if (args.length == 0)
System.out.println("Useage: \r\n java JavaExcCommand <command>");
return;

String[] result = JavaExcCommand.exec(args[0]);
System.out.println("error info:---------------\r\n" + result[1]);
System.out.println("std info:-----------------\r\n" + result[0]);


/*
* 标准流与错误流读取线程
*/
private static class ReadThread extends Thread
private InputStream is;

private ArrayList result = new ArrayList();

public boolean flag;// 流是否读取完毕

public ReadThread(InputStream is)
this.is = is;


// 获取命令执行后输出信息,如果没有则返回空""字符串
protected String getResult()
byte[] byteArr = new byte[result.size()];
for (int i = 0; i < result.size(); i++)
byteArr[i] = ((Byte) result.get(i)).byteValue();

return new String(byteArr);


public void run()
try
int readInt = is.read();
while (readInt != -1)
result.add(Byte.valueOf(String.valueOf((byte) readInt)));
readInt = is.read();


flag = true;// 流已读完
catch (Exception e)
e.printStackTrace();




Java 实现 ssh命令 登录主机执行shell命令

Java 实现 ssh命令 登录主机执行shell命令


 

1、SSH命令

SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。SSH在正确使用时可弥补网络中的漏洞。SSH客户端适用于多种平台。几乎所有UNIX平台—包括HP-UXLinuxAIXSolarisDigital UNIXIrix,以及其他平台,都可运行SSH。

 

实际工作中,我们经常使用客户端工具(比如:Secure CRT,Xshell,MobaXterm等)SSH到主机上,执行一些操作命令。

如何使用Java语言实现SSH 连接主机,并执行Shell命令呢?

 

2、Java 实现 SSH命令 

1)代码实现如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;

import org.apache.commons.lang3.StringUtils;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;


public class SshUtil {
    private static String DEFAULT_CHAR_SET = "UTF-8";
    private static String tipStr = "=======================%s=======================";
    private static String splitStr = "=====================================================";
 
    /**
     * 登录主机
     * @return
     *      登录成功返回true,否则返回false
     */
    public static Connection login(String ip, String userName, String password){
        boolean isAuthenticated = false;
        Connection conn = null;
        long startTime = Calendar.getInstance().getTimeInMillis();
        try {
            conn = new Connection(ip);
            conn.connect(); // 连接主机

            isAuthenticated = conn.authenticateWithPassword(userName, password); // 认证
            if(isAuthenticated){
                System.out.println(String.format(tipStr, "认证成功"));
            } else {
                System.out.println(String.format(tipStr, "认证失败"));
            }
        } catch (IOException e) {
            System.err.println(String.format(tipStr, "登录失败"));
            e.printStackTrace();
        }
        long endTime = Calendar.getInstance().getTimeInMillis();
        System.out.println("登录用时: " + (endTime - startTime)/1000.0 + "s\\n" + splitStr);
        return conn;
    }
 
    /**
     * 远程执行shell脚本或者命令
     * @param cmd
     *      即将执行的命令
     * @return
     *      命令执行完后返回的结果值
     */
    public static String execute(Connection conn, String cmd){
        String result = "";
        Session session = null;
        try {
            if(conn != null){
                session = conn.openSession();  // 打开一个会话
                session.execCommand(cmd);      // 执行命令
                result = processStdout(session.getStdout(), DEFAULT_CHAR_SET);

                //如果为得到标准输出为空,说明脚本执行出错了
                if(StringUtils.isBlank(result)){
                    System.err.println("【得到标准输出为空】\\n执行的命令如下:\\n" + cmd);
                    result = processStdout(session.getStderr(), DEFAULT_CHAR_SET);
                }else{
                    System.out.println("【执行命令成功】\\n执行的命令如下:\\n" + cmd);
                }
            }
        } catch (IOException e) {
            System.err.println("【执行命令失败】\\n执行的命令如下:\\n" + cmd + "\\n" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
            if (session != null) {
                session.close();
            }
        }
        return result;
    }

    /**
     * 解析脚本执行返回的结果集
     * @param in 输入流对象
     * @param charset 编码
     * @return
     *       以纯文本的格式返回
     */
    private static String processStdout(InputStream in, String charset){
        InputStream stdout = new StreamGobbler(in);
        StringBuffer buffer = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout, charset));
            String line = null;
            while((line = br.readLine()) != null){
                buffer.append(line + "\\n");
            }
        } catch (UnsupportedEncodingException e) {
            System.err.println("解析脚本出错:" + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("解析脚本出错:" + e.getMessage());
            e.printStackTrace();
        }
        return buffer.toString();
    }

    public static void main(String[] args){
        String ip = "192.168.123.234";   // 此处根据实际情况,换成自己需要访问的主机IP
        String userName = "root";
        String password = "password";
        Connection conn =  SshUtil.login(ip, userName, password);

        String cmd = "cd /home/miracle&&pwd&&ls&&cat luna.txt";
        String result = SshUtil.execute(conn, cmd);
        System.out.println(splitStr + "\\n执行的结果如下: \\n" + result + splitStr);
    }
}

 

2)运行结果如下:

=======================认证成功=======================
登录用时: 0.859s
=====================================================
【执行命令成功】
执行的命令如下:
cd /home/miracle&&pwd&&ls&&cat luna.txt
=====================================================
执行的结果如下: 
/home/miracle
luna.txt
Hello, I\'m SshUtil.
Nice to meet you.^_^
=====================================================

 

3)pom.xml 引用添加如下:

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <!-- ssh  -->
        <dependency>
            <groupId>ch.ethz.ganymed</groupId>
            <artifactId>ganymed-ssh2</artifactId>
            <version>262</version>
        </dependency>

 

 

PS:

关于Maven依赖的 jar包 下载问题,请参考如下博文:

https://www.cnblogs.com/miracle-luna/p/11863679.html

 

Java 实现 bash命令
https://www.cnblogs.com/miracle-luna/p/12050728.html

 

Java 实现 ssh命令 登录主机执行shell命令
https://www.cnblogs.com/miracle-luna/p/12050367.html

 

Java 实现 telnet命令 验证主机端口的连通性
https://www.cnblogs.com/miracle-luna/p/12049658.html

 

Java 检查IPv6地址的合法性
https://www.cnblogs.com/miracle-luna/p/12041780.html

 

Java 实现判断 主机是否能 ping 通
https://www.cnblogs.com/miracle-luna/p/12026797.html

以上是关于如何利用java过程执行操作系统命令的主要内容,如果未能解决你的问题,请参考以下文章

记一次渗透测试过程中的Zabbix命令执行利用

Java 实现 ssh命令 登录主机执行shell命令

MSSQL代理工作服务器远程命令执行

Hadoop详解——HDFS的命令,执行过程,Java接口,原理详解。RPC机制

168Java调用EXE并利用多线程接收EXE的输出流

168Java调用EXE并利用多线程接收EXE的输出流