2

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
    "Dir" is not an executable command, it is part of the command processor, you need to execute it through "cmd" – MadProgrammer Apr 18 '13 at 22:01
  • @MadProgrammer I've realized that - still not sure how to do that in such a way as to be generic to the platform. –  Apr 18 '13 at 22:02
  • Sorry, checking out some answers, try having a look at [this](http://stackoverflow.com/questions/4031390/executing-dos-commands-from-java) – MadProgrammer Apr 18 '13 at 22:03
  • @MadProgrammer Hmm, that's a good lead. It still doesn't quite solve the problem, though - it doesn't allow for a sequence of commands. –  Apr 18 '13 at 22:04

1 Answers1

0

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();
            }

        }

    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    Except `ProcessBuilder` gives no way to run a second command; I need to run multiple sequential commands in the same prompt. –  Apr 18 '13 at 23:43
  • So? Neither does `Runtime#exec`, you would simply need to continue creating new instances. In fact, I just wrote a class that wraps this all up nicely and provides threaded callbacks. So now I just pass a series of `String`s to the class attach a listener and voila... – MadProgrammer Apr 18 '13 at 23:45
  • But that's the point of my question: I need the commands in the same prompt. –  Apr 18 '13 at 23:49
  • I suppose... not the most optimal solution, but it'll work. Thank you for the help! –  Apr 19 '13 at 00:22
  • I did something similar a long time ago, but I wrote the batch file at runtime based on the some other variables... – MadProgrammer Apr 19 '13 at 00:27
  • Yeah, though this is going to be running on multiple platforms, so it'll be a little tricky. –  Apr 19 '13 at 00:34
  • Talking with the OS in this way always is ;) – MadProgrammer Apr 19 '13 at 00:36