java shell for executing/coordinating processes?

前端 未结 4 455
萌比男神i
萌比男神i 2021-01-14 06:20

I know about using Runtime.exec, you pass it a native program to run + arguments. If it\'s a regular program, you can run it directly. If it\'s a shell script, you have to r

相关标签:
4条回答
  • 2021-01-14 06:37

    Ok, I've worked it out:

    Basically, you need to invoke bash with a "-s" and then write the full command string to it.

    public class ShellExecutor {
    
      private String stdinFlag;
      private String shell;
    
      public ShellExecutor(String shell, String stdinFlag) 
      {
        this.shell = shell;
        this.stdinFlag = stdinFlag;
      }
    
      public String execute(String cmdLine) throws IOException 
      {
        StringBuilder sb = new StringBuilder();
        Runtime run = Runtime.getRuntime();
        System.out.println(shell);
        Process pr = run.exec(cmdLine);
        BufferedWriter bufWr = new BufferedWriter(
            new OutputStreamWriter(pr.getOutputStream()));
        bufWr.write(cmdLine);
        try 
        {
          pr.waitFor();
    } catch (InterruptedException e) {}
        BufferedReader buf = new BufferedReader(
            new InputStreamReader(pr.getInputStream()));
        String line = "";
        while ((line = buf.readLine()) != null) 
        {
            sb.append(line + "\n");
        }
        return sb.toString();
      }
    }
    

    Then use it like this:

    ShellExecutor excutor = new ShellExecutor("/bin/bash", "-s");
    try {
      System.out.println(excutor.execute("ls / | sort -r"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    

    Obviously, you aught to do something with the error string but this is a working example.

    0 讨论(0)
  • 2021-01-14 06:37

    You can use the ProcessBuilder API provided by java.

    Runtime.getRuntime().exec(...) take either an array of strings or a single string. The single-string overloads of exec() will tokenise the string into an array of arguments, before passing the string array onto one of the exec() overloads that takes a string array. The ProcessBuilder constructors, on the other hand, only take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument. Either way, the arguments obtained are then joined up into a string that is passed to the OS to execute.

    Find more details at the below link Difference between ProcessBuilder and Runtime.exec()

    Sample program to execute the commands.

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.lang.reflect.Field;
    import java.util.List;
    
    public class ProcessBuilderTest {
        static ProcessBuilder processBuilder = null;
        static Process spawnProcess = null;
        static int exitValue;
        static int pid;
        static List<String> commands;
    
        public static void main(String[] args) {
            runSqoop();
        }
    
        public static void runSqoop() {
            String[] commands = { "ssh", "node", "commands" };
            processBuilder = new ProcessBuilder(commands);
            try {
                System.out.println("Executing " + commands.toString());
                spawnProcess = processBuilder.inheritIO().start();
                try {
                    exitValue = spawnProcess.waitFor();
                    pid = getPID(spawnProcess);
                    System.out.println("The PID is " + pid);
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
                System.out.println("Process exited with the status :" + exitValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static int getPID(Process process) {
            try {
                Class<?> processImplClass = process.getClass();
                Field fpid = processImplClass.getDeclaredField("pid");
                if (!fpid.isAccessible()) {
                    fpid.setAccessible(true);
                }
                return fpid.getInt(process);
            } catch (Exception e) {
                System.out.println(e.getMessage());
                return -1;
            }
        }
    
    }
    
    0 讨论(0)
  • 2021-01-14 06:44

    Since JDK 1.5 there is java.lang.ProcessBuilder which handles std and err streams as well. It's sort of the replacement for java.lang.Runtime

    0 讨论(0)
  • 2021-01-14 06:49

    You've always been able to handle streams with Runtime.exec

    e.g.

    String cmd = "ls -al";
        Runtime run = Runtime.getRuntime();
        Process pr = run.exec(cmd);
        pr.waitFor();
        BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line = "";
        while ((line=buf.readLine())!=null) {
            System.out.println(line);
        }
    

    However, if you want to put shell characters such as pipe and redirect in there you'd have to write your own command line parser which links up the streams. As far as I know there hasn't one been written. That being said, could you just invoke bash from Java with a -c "ls | sort" for example and then read the input. Hmm time to do some testing.

    0 讨论(0)
提交回复
热议问题