Runtime.getRuntime (). Exec ("C: \ cygwin \ bin \ bash.exe") has no input to read

I am trying to execute a new process and read its input stream in Java. I have successfully used Runtime.getRuntime (). Exec (String) to start and receive input from multiple processes. However, when I try to use exec for some other processes, the method blocks the input stream and it seems that there is no input. What could cause the input stream to be empty for some of these processes? In particular, I wonder why bash.exe does not output anything.

I wrote a JUnit test case to demonstrate this problem:

import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import junit.framework.TestCase; public class TestExec extends TestCase { public void testExec() throws IOException { List<InputPrinter> threads = new ArrayList<InputPrinter>(); // Create a process for each of the commands and make sure that // it outputs at least one line to its input stream. threads.add(testExec("cmd")); threads.add(testExec("java")); threads.add(testExec("C:/cygwin/bin/vim-nox.exe")); // These bottom two fail, even though executing these // commands in cmd.exe results in immediate output threads.add(testExec("javac")); threads.add(testExec("C:/cygwin/bin/bash.exe")); // Give the threads a second to execute try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); fail(); } // Test that each command had input to read for(InputPrinter ip : threads) { assertTrue(ip.command + " has not read any input", ip.hasRead); } } // Starts a process for the given command and returns an // InputPrinter that can be used to check if the process // has had an input to read. public InputPrinter testExec(String command) throws IOException { Process proc = Runtime.getRuntime().exec(command); InputStream in = proc.getInputStream(); InputPrinter ip = new InputPrinter(in, command); new Thread(ip).start(); return ip; } // Simple Runnable to read from an InputStream. hasRead will be // true if at least one input has been read from the stream private class InputPrinter implements Runnable { InputStream in; String command; boolean hasRead; public InputPrinter(InputStream in, String command) { this.in = in; this.command = command; this.hasRead = false; } // Loop indefinitely while printing any received input public void run() { try { final byte[] b = new byte[1024]; while (true) { int n = in.read(b); if (n > 0) { System.out.print(new String(Arrays.copyOf(b, n))); hasRead = true; } } } catch (IOException e) { e.printStackTrace(); fail(); } } } } 

EDIT:

As far as I know, if the program does not use stdout or stderr, I should not see anything on the Windows command line. What I expect to see when starting the bash process is "bash -3.2 $", the same thing that I see when I open the command prompt and run "bash.exe":

 Microsoft Windows [Version 6.1.7600] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\cygwin\bin>bash.exe bash-3.2$ 
+2
java inputstream process cygwin runtime
source share
2 answers

Regardless of Java, as far as I know, you can output output (or input) from / to bash only when it is run as a script, and not when it is run as an interactive shell (in this case you can only pass cmd parameters).

In other words, when you run bash from cmd, as you mention in the comment, you see the output, but it is contained in the bash process, it does not output that bash sends back to the parent cmd.

As for the javac process, it actually sends the output to the error stream. Try starting with cmd javac 1>null and javac 2>null and you will see the difference.
Have you looked at the api here ? You can try to use ProcessBuilder and redirect the error stream back to the main input stream, it will be much easier to work with processes this way.

+2
source share

Usually a process has not only one, but also two output streams. It:

  • stdout, which can be read using getInputStream ()
  • stderr, which can be read using the getErrorStream () method

Javac writes stderr, not stdout, so you are not reading its output.

Because it is inconvenient to read both of them (a few years ago I had to write an additional thread for this), they introduced a new API for system processes, namely ProcessBuilder, which allows you to redirect stderr to stdout.

Just replace the lines

  Process proc = Runtime.getRuntime().exec(command); InputStream in = proc.getInputStream(); 

from

  ProcessBuilder pb = new ProcessBuilder(command); pb.redirectErrorStream(true); Process proc = pb.start(); 

add the required import and your test will succeed :).

+2
source share

All Articles