How do I execute a sequence of related console com

2019-08-04 14:17发布

问题:

I'm currently working on a project where a client receives shell/console commands from a server, and must execute them.

How do I get Java to run these commands from within either a shell or a command prompt? I'm hoping to be able to disregard the platform type - and not have to specify shell or command prompt - but if I can't, then that's okay.

I must be able to send a sequence of related commands, not just one command. This means that the shell/prompt cannot exit or close between commands.

My current code, as follows, allows for the execution of a sequence of programs, but these commands must somehow be piped into a shell/command prompt, from which the output must be read.

ArrayList<String> comDat = new ArrayList<>();

while(true) {
    String input = con.recv();
    System.out.println("> " + input);

    if(!input.equals("EOF")) comDat.add(input); else {
        String[] s = new String[comDat.size()];
        for(int i = 0; i < comDat.size(); i++) s[i] = comDat.get(i);

        System.out.println("---Command sequence executing---");
        Process p = Runtime.getRuntime().exec(s);
        p.waitFor();

        System.out.println("---ErrorStream output---"); String line = "";
        BufferedReader errStream = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        while((line = errStream.readLine()) != null) System.out.println("< " + line);

        System.out.println("\n---OutputStream output---"); line = "";
        BufferedReader outStream = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while((line = errStream.readLine()) != null) System.out.println("< " + line);
    }
    Thread.sleep(200);
}

Thanks for the help!

回答1:

The basic premise revoles around the fact the dir isn't an external command but is function of cmd.

I would avoid BufferedReaders when reading the output of a process as not all processes use new lines when sending output (such as progress indicators), instead you should read char for char (IMHO).

You should us ProcessBuilder instead of Runtime#exec. It provides better management and allows you to redirect the error stream into the input stream, making it easier to read the input.

import java.io.IOException;
import java.io.InputStream;

public class TestProcessBuilder {

    public static void main(String[] args) {

        try {
            ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "dir");
            pb.redirectError();
            Process p = pb.start();
            InputStreamConsumer isc = new InputStreamConsumer(p.getInputStream());
            isc.start();
            int exitCode = p.waitFor();

            isc.join();
            System.out.println("Process terminated with " + exitCode);
        } catch (IOException | InterruptedException exp) {
            exp.printStackTrace();
        }

    }

    public static class InputStreamConsumer extends Thread {

        private InputStream is;

        public InputStreamConsumer(InputStream is) {
            this.is = is;
        }

        @Override
        public void run() {

            try {
                int value = -1;
                while ((value = is.read()) != -1) {
                    System.out.print((char)value);
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }

        }

    }
}