-1

Using

String cmdString = "cmd.exe /c start python ";
Process p = Runtime.getRuntime().exec(cmdString);

I can open the command prompt and run python. I now want to interact with the command prompt. I have read that using

public static void main(String[] args)
{

    BufferedWriter writerToProc;

    String scriptPath = "C:\\Users\\MichaelMi\\Documents\\SourceTree\\NODE-Sensor-Configurator\\src\\application\\resources\\BACnet-CMD-Line-Upgrader\\UpgradeApplication.py";
    String iniPath = "C:\\Users\\MichaelMi\\Documents\\SourceTree\\NODE-Sensor-Configurator\\src\\application\\resources\\BACnet-CMD-Line-Upgrader\\BACpypes.ini";

    String execString  = "python " + scriptPath + " --ini " + iniPath;
    String cmdString = "cmd.exe /c start " + execString ;

    try {
        Process p = Runtime.getRuntime().exec(cmdString);


        writerToProc = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));

        writerToProc.write(cmdString);
        writerToProc.flush();

        writerToProc.write("whois\n");
        writerToProc.flush();

        readErrors(p);
        readOutput(p);

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

public static void readOutput(Process p)
{
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
    Runnable task = new Runnable() {

        @Override
        public void run() {
            try {
                if(stdInput.ready())
                {
                    stdInput.lines().forEach((l) -> System.out.println(l));
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    Thread backgroundThread = new Thread(task);
    backgroundThread.setDaemon(true);
    backgroundThread.start();
}

public static void readErrors(Process p)
{
    BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    Runnable task = new Runnable() {

        @Override
        public void run() {
            try {
                if(stdError.ready())
                {
                    stdError.lines().forEach((l) -> System.out.println(l));
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    Thread backgroundThread = new Thread(task);
    backgroundThread.setDaemon(true);
    backgroundThread.start();
}

Is supposed to allow me to write to the open command prompt. However this is not working for me. I am getting no exceptions thrown or status errors. I simply do not know how to write to an open command prompt.

Michael Miner
  • 964
  • 2
  • 17
  • 39
  • How do you know that you're getting no errors or exceptions? Are you reading from the Process's InputStream? The ErrorStream? And in separate threads? Please show us your [mcve] code so we can see *exactly* what you're doing and more importantly, what you may be doing wrong. Also, don't use Runtime but rather the more recent ProcessBuilder. also the cmd String should be an array or ArrayList of Strings. – Hovercraft Full Of Eels Jul 27 '18 at 17:36
  • I edited the post to show the entire code. The stdInput and stdError are never ready. I never end up in the catch of the try catch. Nothing is ever posted to my opened command prompt – Michael Miner Jul 27 '18 at 17:42
  • You may never know since all is being run in the same thread with blocking code. Please consider separating your input and output into different threads. – Hovercraft Full Of Eels Jul 27 '18 at 17:43
  • 1
    Don’t start a window, start python: Try `String cmdString = "python";` – Bohemian Jul 27 '18 at 17:45
  • I have not ever seen .isReady used in any code examples for reading from a buffer. But could work. You would want to do what @HovercraftFullOfEels said; you could then write a parser that parses the stream and passes it to a handler or just write the code into the thread. ```BufferedReader br = new BufferedReader(fr); String s = null; while ((s=br.readLine())!=null) { System.out.println(s); }``` is the typical method for reading from a reader. – Mr00Anderson Jul 27 '18 at 17:46
  • I added more code. I put the error and output functions into threads. With my cmdString I open the prompt and run my python script. The next lines that are supposed to write 'whois'. That is never written to the newly opened prompt – Michael Miner Jul 27 '18 at 17:54
  • see the duplicates on how to interact with the output of external processes correctly. –  Jul 27 '18 at 19:19

2 Answers2

0

I see two problems in your code:

One problem is the used command-line:

cmd.exe /c start python This starts a new cmd.exe instance which itself the uses start to start a detached python process. The detached process is therefore not connected to your BufferedReader/BufferedWriter.

Your second problem is that python does not execute your "1+1" via stdin. You can simply verify that by creating a file test with the context 1+1\n and execute it on the console: python < test. You will see no output.

See also piping from stdin to a python code in a bash script.

Robert
  • 39,162
  • 17
  • 99
  • 152
  • Well that makes perfect sense. So I already know that I can start a python script and send commands to it. I already have code working which does that. Is there a way to start my python script and see the output in a command prompt window? – Michael Miner Jul 27 '18 at 18:04
  • Do you want to see the output or read it from within Java? The first is easy: just execute `cmd.exe /c start python C:/pathxyz/yourpythonfile.py`. Make sure your python file ends with `time.sleep(5)` otherwise the window is closed directly when your script finishes. – Robert Jul 27 '18 at 18:15
  • My issue is that the script waits for 3 commands. Whois, readhexfile, and sendfile. The send file takes 4 minutes. I am finding it difficult to update my java app UI since the send is blocking. My thought to fix this and put users at ease is to open a command prompt that will show them the progess – Michael Miner Jul 27 '18 at 18:17
  • My be executing the python scripts from within your Java program via Jython is better? – Robert Jul 27 '18 at 18:18
  • So I have code that can execute the script. The whole issue is the UI sitting there for 4 minutes with no updates for the end user to see. – Michael Miner Jul 27 '18 at 18:19
-1

In this case you need to close the input stream before you can read the output streams of the python process. If anyone knows a better way please let us know.

public static void main(String[] args) {
    String cmdString = "python";
    try {
        ProcessBuilder pb = new ProcessBuilder(cmdString);
        Process pr = pb.start();
        try (BufferedReader readerOfProc = new BufferedReader(
                new InputStreamReader(pr.getInputStream()));
                BufferedReader errorsOfProc = new BufferedReader(
                        new InputStreamReader(pr.getErrorStream()))) {

            try (BufferedWriter writerToProc = new BufferedWriter(
                    new OutputStreamWriter(pr.getOutputStream()));) {
                writerToProc.write("myVar=1+1\r\n");
                writerToProc.write("print(myVar)\r\n");
                writerToProc.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }

            String s;
            while ((s = readerOfProc.readLine()) != null) {
                System.out.println("stdout: " + s);
            }
            while ((s = errorsOfProc.readLine()) != null) {
                System.out.println("stdout: " + s);
            }

            System.out.println("exit code: " + pr.waitFor());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Hope this helps!

xtratic
  • 4,600
  • 2
  • 14
  • 32