Runtime.getRuntime().exec() method

1. Use the Runtime.getRuntime().exec() method

sshUtil.java

package com.demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

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

public class SSHUtil {
    private String host; // ip
    private String username;
    private String password;

    /**
     * @param host(ip)
     * @param username(User name)
     * @param password(Password)
     */
    public SSHUtil(String host, String username, String password) {
        this.host = host;
        this.username = username;
        this.password = password;
    }

    private Connection conn = null;

    /**
     * connect
     */
    private boolean connect() {
        conn = new Connection(host);
        try {
            conn.connect();
            if (conn.authenticateWithPassword(username, password)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Execute command
     */
    public String execute(String command) {
        if (command == null || "null".equals(command)) {
            return "The incoming command is empty!!!";
        }
        if (!connect()) {
            return "Failed to connect to the server!!!";
        }
        Session session = null;
        try {
            session = conn.openSession();
            session.execCommand(command);
            InputStream stdout = new StreamGobbler(session.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
            StringBuffer sb = new StringBuffer();

            // ExitCode is normally 0
            // 1: Error report, 2: Command misuse, 126: command cannot be executed, 127: command not found, 130:ctrl+c end, 255: return code out of range
            sb.append("ExitCode: " + session.getExitStatus() + "\n");
            while (true) {
                String line = br.readLine();
                if (line == null)
                    break;
                sb.append(line + "\n");
            }
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return "error";
        } finally {
            if (conn != null) {
                conn.close();
            }
            if (session != null) {
                session.close();
            }
        }
    }
}

SSHMain.java

package com.demo;

public class SSHMain {

    public static void main(String[] args) {
        SSHUtil sshUtil=new SSHUtil("1.117.23.51","root","xxxx");

        String c1="cd /";
        String e1 = sshUtil.execute(c1);
        System.out.println(e1);

        String c2="pwd";
        String e2 = sshUtil.execute(c2);
        System.out.println(e2);
        
    }
}

Execution results:

Runtime.getRuntime().exec() of command execution

In java, RunTime.getRuntime().exec() implements the need to call the server command script to execute functions.

Usage:

public Process exec(String command)-----Executes the specified string command in a separate process.
public Process exec(String [] cmdArray)---Executes the specified commands and variables in a separate process
public Process exec(String command, String [] envp)----Executes the specified commands and variables in a stand-alone process in the specified environment
public Process exec(String [] cmdArray, String [] envp)----Executes the specified commands and variables in a stand-alone process in the specified environment
public Process exec(String command,String[] envp,File dir)----Executes the specified string command in a stand-alone process with the specified environment and working directory
public Process exec(String[] cmdarray,String[] envp,File dir)----Executes the specified commands and variables in a separate process of the specified environment and working directory

give an example:

1. Open Notepad under windows

RunTime.getRuntime().exec(String command);

Under windows, it is equivalent to directly calling / starting / searching programs and files, such as

Runtime.getRuntime().exec("notepad.exe");  -------open windows Take down the Notepad.

2,public Process exec(String [] cmdArray);

Under Linux:

Runtime.getRuntime().exec(new String[]{"/bin/sh","-c", cmds});

Under Windows:

Runtime.getRuntime().exec(new String[]{ "cmd", "/c", cmds});

example:

String command = "find " + source.getRoute() + " -name '" +source.getName();  

Process process = Runtime.getRuntime().exec(new String[] {"/bin/sh","-c",command});

Supplement: #/ bin/bash and #/ The difference between bin/sh

# Is an indicator indicating the path, / bin/bash and / bin/sh specify the program path of the script parser

bash is the full version of sh. bash is fully compatible with sh commands, but not vice versa

OPTIONS:

-c string this option indicates that the string contains a command, such as bash -c ls~

-i make Bash run interactively

-r make Bash run in a restricted manner

– login enables Bash to run as a login Shell

– make Bash comply with POSIX standards

– verbose causes Bash to display all the input lines it reads

– help print Bash usage information

– version print version information

In depth:

Several uses of Process:

1.destroy(); Kill child process

2.exitValue(); Returns the exit value of the child process. A value of 0 indicates normal termination

3.getErrorStream(); Get the input stream of your own process error output

4.getInputStream(); Here is the input stream to get the output of the child process

5.getOutputStream(); Gets the output stream of the child process input

6.waitFor(); This causes the current thread to wait. If necessary, wait until the Process represented by the Process object has been terminated. If the sub Process has been terminated, this method returns immediately. If the sub Process has not been terminated, the calling thread will be blocked until the sub Process is pushed out. According to the Convention, 0 indicates normal termination

The explanation here may not be clear enough. First, the subprocess refers to the process we use the exec method to execute. Take getInputStream() method as an example. The output of the subprocess is the input to the process of our program, and all are the input streams relative to java programs.

Note: in java, calling runtime threads to execute scripts is very resource consuming, so don't use them frequently!

When calling the runtime to execute the script, the JVM actually opens a sub thread to call the commands of the system where the JVM is located, in which three channels are opened: input stream, output stream and error stream. The output stream is the channel that the sub thread calls.

As we all know, waitFor is executed after the execution command of the sub thread is completed. However, in runtime, if the command to open the program is not closed, the operator thread will not end. For example, the following code.

Code:

​ private static Process p = null;

​ p = Runtime.getRuntime().exec("notepad.exe");

​ p.waitFor();

System.out.println("----------------------------------------- I was executed");

In the above code, open notepad in windows. It should be understood that if we do not manually close Notepad, the output statement will not be executed.

Blocking of process:

When the runtime executes a larger command, the input stream and error stream will continue to enter the buffer stored in the JVM. If the stream in the buffer is not read and filled, it will cause runtime blocking. Therefore, during operations such as large file copying, we also need to constantly read the buffer stream in the JVM to prevent deadlock blocking at runtime.

Use of Java Runtime.exec()

Calling program under windows

Process proc =Runtime.getRuntime().exec("exefile");

Calling program under Linux

Process proc =Runtime.getRuntime().exec("./exefile");

Calling program system commands under windows

String [] cmd={"cmd","/C","copy exe1 exe2"}; 
Process proc =Runtime.getRuntime().exec(cmd);

When calling system commands under Linux, it should be changed to the following format

String [] cmd={"/bin/sh","-c","ln -s exe1 exe2"}; 
Process proc =Runtime.getRuntime().exec(cmd);

Call the system command under windows and pop up the command line window

String [] cmd={"cmd","/C","start copy exe1 exe2"}; 
Process proc =Runtime.getRuntime().exec(cmd);

Call the system command and pop up the terminal window under Linux

String [] cmd={"/bin/sh","-c","xterm -e ln -s exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);

Also, to set the working directory of the caller, you need to

Process proc =Runtime.getRuntime().exec("exeflie",null, new File("workpath"));

The best way to execute a command is to write a bat file or shell script, and then call it, so that modification and implementation is much simpler.

The main way for Java to execute external commands is to call the shell of the platform. CMD is used under windows, and shell is used under Linux or unix. The call to a bat file is demonstrated below, and the results are echoed to the console.

Read bat configuration file

1. Prepare bat file

2. Write code

package com.ssh;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class JavaExeBat {
    public static void main(String[] args) {
        Process process;
        String cmd="D:\\Demo03\\test.bat";
        try {
            //Execute command
            process = Runtime.getRuntime().exec(cmd);
            //Gets the output stream of the command result
            InputStream inputStream = process.getInputStream();
            //Use a read output stream class to read
            InputStreamReader isr = new InputStreamReader(inputStream, Charset.forName("GBK"));
            //Read line with buffer
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            //Until you finish reading
            while ((line=br.readLine())!=null){
                System.out.println(line);
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

3. Implementation results

Using cmd /C

package com.ssh;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class JavaExeBat {
    public static void main(String[] args) {
        Process process;
        //String cmd="D:\\Demo03\\test.bat";
        //String cmd="dir ";
        //String [] cmd={"cmd","/C","start copy exe1.txt exe4.txt"};
        String [] cmd={"cmd","/C","dir "};
        try {
            //Execute command
            process = Runtime.getRuntime().exec(cmd);
            //Gets the output stream of the command result
            InputStream inputStream = process.getInputStream();
            //Use a read output stream class to read
            InputStreamReader isr = new InputStreamReader(inputStream, Charset.forName("GBK"));
            //Read line with buffer
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            //Result output stream
            //Until you finish reading it
            System.out.println("output");
            while ((line=br.readLine())!=null){
                System.out.println(line);
            }

            //Error outflow
            System.out.println("error");
            //Output stream
            InputStream errorStream = process.getErrorStream();
            InputStreamReader error = new InputStreamReader(errorStream, Charset.forName("GBK"));
            BufferedReader erbr=new BufferedReader(error);
            line=null;
            while ((line=erbr.readLine())!=null){
                System.out.println(line);
            }


        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Use multithreading to read cmd commands and output the results

package com.ssh;

import sun.rmi.runtime.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class javaExec {

    public static void main(String[] args) {
        //String[] cmds = new String("cmd", "/c", "dir ");
        String[] cmd = {"cmd", "/C", "dir "};
        runTimeExecutor(cmd);

    }
    public static void runTimeExecutor(String[] cmd){
        Runtime runtime=Runtime.getRuntime();
        try {
            Process process = runtime.exec(cmd);
            InputStream errorStream = process.getErrorStream();
            InputStream inputStream = process.getInputStream();
            readStreamInfo(errorStream,inputStream);
            int i = process.waitFor();
            process.destroy();
            if(i==0){
                System.out.println("The subprocess completed normally");
            }else{
                System.out.println("The child process ended abnormally");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * Read the input stream of the Runtime.exec running subprocess
     */
    public synchronized static void readStreamInfo(InputStream... inputStreams){

        Object o=new Object();
        for(InputStream in:inputStreams){
            new Thread(()->{

                synchronized (o){
                    System.out.println("start");

                    try {
                        BufferedReader br = new BufferedReader(new InputStreamReader(in, Charset.forName("GBK")));
                        String line=null;
                        while ((line=br.readLine())!=null){
                            System.out.println(line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }finally {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    System.out.println("end");
                }

            }).start();
        }
    }
}

StreamGobbler explains

StreamGobbler is an InputStream that uses internal worker threads to continuously use input from another InputStream. It uses buffers to store consumed data. If necessary, the buffer size is automatically adjusted. This class is sometimes very convenient - if you wrap the STDOUT and STDERR InputStreams of a session with an instance of this class, you don't have to worry about the shared windows of STDOUT and STDERR in the low-level SSH-2 protocol, because all incoming data will be consumed by the worker thread immediately. In addition, as a side effect, the stream will be buffered (for example, a single byte read() operation is faster). Other SSH for Java libraries include this function by default in their STDOUT and STDERR InputStream implementations. However, please note that this method also has a disadvantage: if you call the read() method of StreamGobbler not frequently enough and send a large amount of data to the opposite end, you will encounter a shortage of memory due to aggregated data sooner or later (well, it also depends on the Java heap size). Anyway, Joe Average will like this class - a paranoid programmer will never use this method.

Tags: Operation & Maintenance ssh server

Posted on Wed, 03 Nov 2021 02:57:13 -0400 by gillms1