Implementation of Java Calling Shell Command and Script

  • 2021-08-28 20:08:53
  • OfStack

1. Introduction

Sometimes when we run an Java program in Linux, we need to call a few Shell commands and scripts. The Runtime. getRuntime (). exec () method gives us this functionality, and Runtime. getRuntime () gives us the following exec () methods:


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

Among them, cmdarray and command are similar. At the same time, if there is no envp parameter in the parameter or it is set to null, it means that the calling command will be executed in the current program execution environment; If the dir parameter is absent or set to null, it means that the calling command will be executed in the directory where the current program is executing, so it is best to use absolute paths for files and scripts called to other directories. Meaning of each parameter:

cmdarray: An array containing the called command and its arguments. command: 1 specified system command. envp: An array of strings in which the environment variable for each element is set in the format name=value; If the child process should inherit the environment of the current process, the parameter is null. dir: The working directory of the child process; If the child process should inherit the working directory of the current process, the parameter is null.

Careful readers will find that in order to perform the call operation, JVM will start an Process, so we can know whether the call operation is executed correctly by calling the following methods of the Process class:


abstract int waitFor() 
 Causes the current thread to wait, if necessary, 1 Until the  Process  The process represented by the.  

The exit value of the process. By convention, 0 means normal termination; Otherwise, an exception fails.
Also, some Shell commands or scripts are called with return values, so what if we capture those return values or output? To solve this problem, the Process class provides:


abstract InputStream getInputStream() 
 Gets the input stream of the child process.   It is best to buffer the input stream. 

2. Invoke the Shell command

To illustrate the problem here, I will only use tar command for demonstration. The tar command is a packaged command without compression. At the same time, to check that the call to tar is executed properly, I will call the waitFor () method.


private void callCMD(String tarName, String fileName, String... workspace){
 try {
 String cmd = "tar -cf" + tarName + " " + fileName;
//      String[] cmd = {"tar", "-cf", tarName, fileName};
 File dir = null;
 if(workspace[0] != null){
  dir = new File(workspace[0]);
  System.out.println(workspace[0]);
 }
 process = Runtime.getRuntime().exec(cmd, null, dir);
//     process = Runtime.getRuntime().exec(cmd);
 int status = process.waitFor();
 if(status != 0){
  System.err.println("Failed to call shell's command and the return status's is: " + status);
 }
 }
 catch (Exception e){
 e.printStackTrace();
 }
}

Note: If you put a command in an String [], you must have each part of the command as an element in String [], or String [] by dividing the command into spaces.


String[] cmd = {"tar", "-cf", tarName, fileName}; //right
String[] cmd = {"tar -cf", tarName, fileName};  //error

To illustrate what the dir parameter does, I specifically put the Java program in a different directory from the directory hive/to be packaged:


/root/workspace/eclipse/Test/src/edu/wzm/CallShell.java
/root/experiment/hive

If I don't set dir or set dir to null, then fileName has to be a relative path, preferably an absolute path:


call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive", null);
// OR
call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive");

It would be much easier if I set dir to point to the parent directory where hive is located:


call.callCMD("hive.tar", "hive", "/root/experiment/");

3. Call the Shell script

Java calls Shell commands and calls Shell scripts. I will introduce several other aspects here:

Pass parameters to the script; Capture the output of the call; Use of envp.

Pass parameters to the script, which is simple enough to append parameters to the calling command to form String, or String [].

Capture the call output, as mentioned earlier with Process. getInputStream (). However, it is recommended that the input stream is best buffered:


BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));

In addition, envp is one String [], and every element in String [] has the form of name=value. Example: My Linux system does not have the following environment variables, but I write them in the Java code as envp:


val=2
call=Bash Shell

The Shell script I want to call is:/root/experiment/test. sh.


abstract int waitFor() 
 Causes the current thread to wait, if necessary, 1 Until the  Process  The process represented by the.  

0

The Java call code is:


abstract int waitFor() 
 Causes the current thread to wait, if necessary, 1 Until the  Process  The process represented by the.  

1

Output:
/root/experiment/
The argument is: 4
This is a Bash Shell
Cost Time: 24


Related articles: