Java app 'steals' stdin from cmd.exe console - java

I am trying to run a java app as a spawned child process under Windows 7.
The command I am using is in the lines of: java -cp ...list of libs...
The problem is that once the application loads, it doesn't have its own stdin stream but try to uses its parent's stdin, which results in that commands can not be passed to it.
Are there any parameters of 'java.exe' that can twick this behavior, so the child process will have its own stdin?
Thanks
Update:
Sorry I am not a java programmer but could this happen because of this line in the java app I am running:
this(new IO(System.in, System.out, System.err), STANDARD_INPUT_PROMPT, STANDARD_RESULT_PROMPT);
If so, what is an adequate substitute to System.in?

Why not just start a new command prompt that spawns the child process? I don't program much for windows environments much but I got the following to work:
public class Main {
public static void main(String [] args) {
try {
Runtime.getRuntime().exec("cmd /k start cmd /k echo hello");
} catch (Throwable t) {
t.printStackTrace();
}
}
}
If you replaced echo with your subprocess program and hello with necessary arguments then you should be all set to receive stdin. In other words do:
Runtime.getRuntime().exec("cmd /k start cmd /k java -cp ...list of libs...");
There might be a much prettier method of doing this by the way.

Related

Using Java's getRuntime.exec() to Run a Linux Shell Command: How?

Below is a python script that executes a linux bash command "echo Hello World > ./output"
import os
os.system("bash -c \"echo Hello World > ./output\"");
I am trying to do the same with Java. Below is my best effort, following the instructions I found here: Want to invoke a linux shell command from Java
import java.io.IOException;
public class callCommand {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec(
new String[]{"bash","-c",
"\"echo Hello World > ./output\""});
} catch(IOException e) {
e.printStackTrace();
}
}
}
It compiles without issue, and runs without complaint, but no output file is generated.
The extra quotes around echo ... should be removed:
Process p = Runtime.getRuntime().exec(new String[]{
"bash", "-c",
"echo Hello World > ./output"
});
The python version needs extra quotes to tell the underlying system that echo Hello World > ./output is a single argument. The java version explicitly specifies arguments as separate strings, so it doesn't need those quotes.
Also, your version doesn't "run without complaint", you just don't see the complaints, because you don't read the error stream of the created process.
The standard input, output and error streams to/from a system process started from Java are accessed through the methods getOutputStream(), getInputStream() and getErrorStream() of Process.
I recommend you to get the error output produced by your system process:
Process p = Runtime.getRuntime().exec(...);
InputStream input=p.getErrorStream();
do
{
n=input.read(...);
}
while (n>=0);
Be careful: For your actual problem, this would be enough. But for a process which produces a longer error/output, you need to perform the reading of the standard error/output in a separate thread. If not, the system process would block when the error/output buffer is full, and wait till it is externally consumed, and if you place the reading loop just after the process is executed, it will never execute and so, the program will get into a deadlock.

Back to back commands in mac terminal via java Runtime

Basically I have 2 commands I need to execute via a java program the way you would if you were just typing it into terminal.
so like
cd /Users/nameOfUser/Desktop/someFolder/someSubFolder
and then another command I want to execute within that directory. Currently I am doing this:
Process navigate = Runtime.getRuntime().exec("cd /Users/nameOfUser/Desktop/someFolder/someSubFolder");
Process doSomething = Runtime.getRuntime().exec("commandInThatDirectory");
Which doesn't work, it doesn't throw an exception but the second process doesn't seem to take place in the directory specified before it. I am new to processes and runtimes so please bear with me :P.
Is their a way to execute the commands back to back within the same instance of terminal or at least a format for 1 command where you can specify the directory for another command to take place in? I'm a linux user so I don't know mac terminal very well sorry.
It can be done something like this. you can run any command by by placing a semicolon between the commands.
public class Main {
public static void main(String[] args) throws IOException {
ProcessBuilder pb1 = new ProcessBuilder(
"bash",
"-c",
"cd /Users/nameOfUser/Desktop/someFolder/someSubFolder;commandInThatDirectory");
pb1.redirectErrorStream(true);
Process p = pb1.start();
}
}

Run .jar file from java program with arguments

I'm trying to run a jar file from another java program.
Current code:
ProcessBuilder pb = new ProcessBulder("java", "-Djava=\"libs\\native\\windows\"", "-jar", "example.jar", arg1, arg2, arg3);
pb.directory(new File("my\\directory\\folder"));
Process process = pb.start();
When this code is executed i get no error and nothing appears to actually happen.
With ProcessBuilder.start() you start a new thread. The documentation states:
By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process
So, if you don't specifically ask for it, you will never see results from that process (this includes error messages from it's start up).
A way better alternative is not relying on the ProcessBuilder at all. If your callee is a JVM class, just include the JAR on your application's classpath like so:
java -classpath ./example.jar -jar myApp.jar
You're then free to call example's methods:
public class MyApp {
public static void main(String[] args) {
Example.main(new String[] { "bla", "blubb", "blabb" });
}
}

Runtime.getRunTime().exec not behaving like C language "system()" command

In "C", I can run a long blocking process in the background (AND HAVE IT CONTINUE TO RUN) after the starting process has exited.
void main(void)
{
system("some_long_blocking_process &");
exit();
}
// "some_long_blocking_process" is still running here (DESIRED BEHAVIOR)
Java's getRuntime().exec() DOESN'T have this behavior. Instead, "some_long_blocking_process" ends immediately when the Java process ends.
Anyone know how I can recapture this behavior in Java?
I am using Java 1.4 (No process builder)
I specifically am looking to start the long blocking process and to exit immediately (no "waitFor(), etc.)
Things I have already tried (the process runs correctly, but I still get the same undesired behavior)
adding "nohup" and run in foreground ("nohup some_long_process")
adding "nohup" and running in background ("nohup some_long_process &")
run in foreground ("some_long_process")
run in background ("some_long_process &")
THANKS!
Thanks to all the suggestions... I've decided to use jtahlborn's answer (it worked for me)
try this:
String[] cmd = {"/bin/sh", "-c", "yourcommand args"};
Process p = Runtime.getRuntime().exec(cmd);
when redirect stream to /dev/null:
String[] cmd = {"/bin/sh", "-c", "yourcommand args > /dev/null 2>&1 &"};
Process p = Runtime.getRuntime().exec(cmd);
the only way we were able to achieve this with java was to add another layer of script. you need a simple wrapper script which invokes the app you actually want to run, e.g.:
runner.sh:
#!/bin/sh
nohup "$#" > /dev/null 2>&1 &
then invoke "/bin/sh runner.sh the real command" from your java program.
EDIT:
Have your tried this?
Runtime.getRuntime().exec("/bin/sh -c /usr/X11/bin/xterm &")
This worked for me on MacOS.
Previous answer (JDK 1.5, apologies for not reading the question correctly):
To execute a process without waiting you can use the ProcessBuilder
ProcessBuilder pb = new ProcessBuilder("/usr/X11/bin/xterm");
pb.start();
Your problem is probably due to the trailing &. Try removing it.
getRuntime().exec() is more similar to fork() and exec() than system().
system() passes the command to the shell, and it's Bash that understands that the trailing ampersand means to run the process in the background.
getRuntime().exec() parses the command using a StringTokenizer to parse the command, and doesn't do anything with the trailing ampersand. That's simply passed as the first argument to your some_long_blocking_process, which may exit out immediately on the unknown error.
Have you tried spawning a new Thread to run the executable? Try:
new Thread(new Runnable() {
#Override
public void run() {
try {
Runtime.getRuntime().exec(<your exec>);
} catch (IOException e) {
e.printStackTrace();
}
}
}).run();
This way, the main process won't shutdown until the exec has finished running (and the thread has finished).
Also, don't manually call exit() in your application unless you have some overwhelming reason to--the JVM does a good job of detecting when the application has finished on its own. This way, you won't force close threads that are running in the background.

Execute Unix system command from JAVA problem

I am facing a weird issue with executing a system command from JAVA code.
Actually i want to get the Mac OSX system information from my JAVA App.
For that im using
Runtime.getRuntime().exec("system_profiler -detailLevel full");
This is working fine.If i print the output,it is cool.
But i want to write this information to a plist file for future use.For that im using the -xml argument of system_profiler.like,
String cmd = "system_profiler -detailLevel full -xml > "+System.getProperty( "user.home" )+"/sysinfo.plist";
Process p = Runtime.getRuntime().exec(cmd);
Basically this should create a plist file in the current users home directory.
But this seems to be not writing anything to file.
Am i missing something here ?
My Java is more than rusty, so please be gentle. ;-)
Runtime.exec() does not automatically use the shell to execute the command you passed, so the IO redirection is not doing anything.
If you just use:
"/bin/sh -c system_profiler -detailLevel full > path/file.plist"
Then the string will be tokenized into:
{ "/bin/sh", "-c", "system_profiler", "-detailLevel", "full", ">", "path/file.plist" }
Which also wouldn't work, because -c only expects a single argument.
Try this instead:
String[] cmd = { "/bin/sh", "-c", "system_profiler -detailLevel full > path/file.plist" };
Process p = Runtime.getRuntime.exec(cmd);
Of course, you could also just read the output of your Process instance using Process.getInputStream() and write that into the file you want; thus skip the shell, IO redirection, etc. altogether.
Christian.K is absolutely correct. Here is a complete example:
public class Hello {
static public void main (String[] args) {
try {
String[] cmds = {
"/bin/sh", "-c", "ls -l *.java | tee tmp.out"};
Process p = Runtime.getRuntime().exec (cmds);
p.waitFor ();
System.out.println ("Done.");
}
catch (Exception e) {
System.out.println ("Err: " + e.getMessage());
}
}
}
If you weren't using a pipe (|) or redirect (>), then you'd be OK with String cmd = "ls -l *.java", as in your original command.
If you actually wanted to see any of the output in your Java console window, then you'd ALSO need to call Process.getInputStream().
Here's a good link:
Running system commands in Java applications

Categories

Resources