I'm trying to use Runtime.getRuntime().exec() to call a program as if it was called from the terminal, but it just crashes with a fatal error after reading the first file.
In the terminal I run the command like so:
mace4 -c -f inputFile.in > outputFile.out
It works as expected, reading from the first file and outputting in the second one.
In Java I try to run it this way:
String args[] = new String[]{"mace4", "-c", "-f", inputFileName ,">",outputFileName};
try {
String s;
Process proc = Runtime.getRuntime().exec(args, null, new File("/home/user/workDirectory/"));
BufferedReader br = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
proc.waitFor();
proc.destroy();
As soon as the program reaches the end of the first file, it throws this:
Fatal error: read_all_input, file > not found
The program is quite old and I can't seem to find a way to get a more detailed error out of it..
I tried calling it with these arguments {"sh or bash", "-c", "mace4", "-c", "-f", inputFileName ,">",outputFileName} which makes the program run and then freeze (or at least nothing appears in the console)..
Am I calling the terminal command wrong and if yes what should I change?
PS: this is my first question here, if I missed anything, I'm sorry..
It looks like you're trying to use the Bash output redirection operator >. This redirects the output of the program you're running to a file (or another program)
This answer explains how to do this using ProcessBuilder which should work for what you're trying to do here.
For example:
ProcessBuilder pb = new ProcessBuilder("mace4", "-c", "-f", inputFileName);
pb.redirectOutput(new File(outputFileName));
Process p = pb.start();
Related
I want to run a .sh file using java. I want a terminal to be opened and then I can execute another commands in the same terminal and finally destroy it.
I already used ProcessBuilder but I could not accomplish this.
My piece of code:
ProcessBuilder pb = new ProcessBuilder("/home/omar/ros_ws/baxter2.sh");
Process p = pb.start();
This method used to work in another code, but I don't know why it's not working in mine.
Thanks in advance
How do you know that it doesn't execute? Maybe you just aren't seeing its result. You should get p.getInputStream() after executing and print in your console, like:
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
Also if you're using jdk 7+, try:
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();
Does your program output an error, or is your program not interacting with the file?
I would suggest trying the directory method within ProcessBuilder.
Process p = null;
ProcessBuilder pb = new ProcessBuilder("baxter2.sh");
pb.directory("/home/omar/ros_ws");
p = pb.start();
If this doesn't work, you should also look into user permissions for the file that you're trying to access.
I think you should grant the .sh file the executable permission to the OS user used to run the java program by using the below command.
chmod u+x baxter2.sh
I try to run the wavemon command from java and read the output.
But I can't make the Runtime.exec method work.
The echo command in comments works and prints "hello", but the wavemon command just returns "". Wavemon is installed, I even tried it with it's full path (/usr/bin/wavemon) as an argument.
Nothing works.
// call wavemon
Runtime rt = Runtime.getRuntime();
String[] cmd = { "sh", "-c", "wavemon", "-i wlan1", "-d" };
//String[] cmd = { "sh", "-c","echo hello" };
Process proc = rt.exec(cmd);
proc.waitFor();
// read wavemon output into string
Scanner is = new Scanner(new InputStreamReader(proc.getInputStream()));
StringBuffer buffer = new StringBuffer();
while (is.hasNext()) {
buffer.append(is.nextLine());
}
proc.destroy();
System.out.println(buffer.toString());
The output of the wavemon command starts with an empty line, but since I use a scanner, this should not matter?
$ wavemon -i wlan1 -d
Configured device: wlan1 (IEEE 802.11abgn)
Security: WPA, WPA2, TKIP, CCMP
...
A little detail, this code is used in the Spring framework (spring-boot, tomcat container).
You should not need the "sh -c". Try just using only:
String[] cmd = { "wavemon", "-i","wlan1", "-d" };
Also, you should put the waitFor() after reading the lines from the scanner, as this holds the thread until the process is done. However, the process might not finish until you read it's output. You can get even fancier and read all of the streams on separate threads.
This article has all the details on it http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html
I need to run two commands Linux using java code like this:
Runtime rt = Runtime.getRuntime();
Process pr=rt.exec("su - test");
String line=null;
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
while((line=input.readLine()) != null) {
System.out.println(line);
}
pr = rt.exec("whoami");
input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
line=null;
while((line=input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exited with error code "+exitVal);
} catch(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
The problem is the output of the second command ("whoami") doesn't display the current user which used on the first command ("su - test")!
Is there any problem on this code please?
In the general case, you need to run the commands in a shell. Something like this:
Process pr = rt.exec(new String[]{"/bin/sh", "-c", "cd /tmp ; ls"});
But in this case that's not going to work, because su is itself creating an interactive subshell. You can do this though:
Process pr = rt.exec(new String[]{"su", "-c", "whoami", "-", "test"});
or
Process pr = rt.exec(new String[]{"su", "test", "-c", "whoami"});
Another alternative is to use sudo instead of su; e.g.
Process pr = rt.exec(new String[]{"sudo", "-u", "test", "whoami"});
Note: while none of the above actually require this, it is a good idea to assemble the "command line" as an array of Strings, rather than getting exec to do the "parsing". (The problem is that execs splitter does not understand shell quoting.)
As stated in the Javadoc for Runtime.exec():
Executes the specified string command in a separate process.
each time you execute a command via exec() it will be executed in a separate subprocess. This also means that the effect of su ceases to exist immediately upon return, and that's why the whoami command will be executed in another subprocess, again using the user that initially launched the program.
su test -c whoami
will give you the result you want.
If you want to run multiple commands in a way the commands would execute in a subshell if need be see the response here
How can I run multiple commands in just one cmd windows in Java? (using ProcessBuilder to simulate a shell)
I'm trying a new approach to a hitch I've been stuck on. Instead of using expect4j for my SSH connection, (I couldn't figure out a way past blocking consumer runs and issues with closures, see past posts for more info on that if you're knowledgeable and feeling saintly,) I'm going to try to use an expect script. I have a runtime exec coded in to a button.onclick, see below. Why am I getting a 127 exit value? I basically just need this expect script to ssh in, run a single set of expect and send, give me the readout, and that's it...
I'm using cygwin. Not sure if that's relevant to why this isn't working...is my sh-bang line pointing to the right place? My cygwin install is a full install, all packages, in C:\cygwin.
Why am I getting a 127 exit value instead of a readout from my server, and how do I alleviate this?
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec( new String [] {"C:\\cygwin\\bin\\bash.exe", "C:\\scripts\\login.exp"});
InputStream stdin = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stdin);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<OUTPUT>");
while ( (line = br.readLine()) != null)
System.out.println(line);
System.out.println("</OUTPUT>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
#!/usr/bin/expect -f
spawn ssh userid#xxx.xxx.xxx.xxx password
match_max 100000
expect "/r/nDestination: "
send -- "xxxxxx\r"
expect eof
The problem is that you use bash to execute an expect script. You need to use expect to execute an expect script, or bash to execute an expect script by means of a shell commandline (that would be Process proc = rt.exec( new String [] {"C:\\cygwin\\bin\\bash.exe", "-c", "C:\\scripts\\login.exp"});, note the "-c" which I have inserted) which makes use of the magic shebang at the top of your script. Or better, use only the shebang: Process proc = rt.exec( new String [] {"C:\\scripts\\login.exp"});
The exit value of 127 is a special exit value, and tells you "command not found". Which makes sense as you expect script contains many words for which no system binaries or shell builtins exist.
I'm trying out the Runtime.exec() method to run a command line process.
I wrote this sample code, which runs without problems but doesn't produce a file at c:\tmp.txt.
String cmdLine = "echo foo > c:\\tmp.txt";
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(cmdLine);
BufferedReader input = new BufferedReader(
new InputStreamReader(pr.getInputStream()));
String line;
StringBuilder output = new StringBuilder();
while ((line = input.readLine()) != null) {
output.append(line);
}
int exitVal = pr.waitFor();
logger.info(String.format("Ran command '%s', got exit code %d, output:\n%s", cmdLine, exitVal, output));
The output is
INFO 21-04 20:02:03,024 - Ran command
'echo foo > c:\tmp.txt', got exit code
0, output: foo > c:\tmp.txt
echo is not a standalone command under Windows, but embedded in cmd.exe.
I believe you need to invoke a command like "cmd.exe /C echo ...".
The > is intrepreted by the shell, when echo is run in the cmmand line, and it's the shell who create the file.
When you use it from Java, there is no shell, and what the command sees as argument is :
"foo > c:\tmp.txt"
( Which you can confirm, from the execution output )
You can't just pass "> c:\tmp.txt" to Runtime.exec as part of the command line to make redirection happen. From the Javadocs: "All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(), getErrorStream())."
If you want to redirect output to a file, to the best of my knowledge the only way to do that would be to open the file in Java, do getInputStream, and then read from the process's input stream and write to the desired file.