How to execute a file using Java Runtime - java

I'm trying to execute a simple batch file from java using Runtime.getRuntime().exec(command);
but facing issues,
below is my code snippet
public class Path {
public static void main(String args[]){
String[] command = new String[3];
command[0]="cmd";
command[1]="/C";
command[2]="D:/alt/a.bat";
Process p;
try {
p = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(
p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(
p.getErrorStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
and the batch a.bat has ant -f runme.xml test in it
and runme.xml resides in D:/alt physical location which has a target test, so far so good
but when i try to execute the java code above, below is the ouput
D:\RCPStack\Path>ant -f runme.xml test Buildfile: runme.xml does not
exist! Build failed
when i execute manually it works fine,seems to be the problem is with the code
below is manual execution output
how to tackle this(i don't know if the code is incorrect) and handle as a best practice

Try to use the method Runtime.exec(String cmd, String[] envp, File dir)
to set the working directory to D:/alt/.
This is because Ant must be executed in the directory where runme.xml is so Ant can find it.

p=Runtime.getRuntime().exec("cmd /c ant -f runme.xml test", null, new File("D:/alt"));//works
or
p=Runtime.getRuntime().exec("cmd /c a.bat", null, new File("D:/alt"));//works

Related

How to write and run terminal command to be execute in java program

String str;
Process p;
try {
String command = "wmctrl -l|awk '{$1=\"\"; $2=\"\"; $3=\"\"; print}'";
p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((str = br.readLine()) != null) {
activeWindowtitles.add(str);
System.out.println(str);
}
p.waitFor();
p.destroy();
} catch (Exception ex) {
}
I am writing a java code to get all applications name in Linux system. I found a command to achieve this. I ran this command in Terminal and it works fine. But it is not working in Java code as i want only applications name instead of other details. The command is "wmctrl -l | awk '{$1=""; $2=""; $3=""; print}'"
I am getting full output after executing this in java code.
Please tell me how to write this command properly..
Thanks
Personally I would put the wmctrl command in a script and do something like this:
public static List<String> getRunningApps(String executablePath) throws IOException, InterruptedException {
final String ERR_LOG_PATH = "stderr.log";
List<String> result = new ArrayList<>();
ProcessBuilder pb = new ProcessBuilder(executablePath);
pb.redirectError(new File(ERR_LOG_PATH));
Process p = pb.start();
int exitCode = p.waitFor();
if (exitCode != 0) {
throw new RuntimeException(String.format("Error get apps. Check error log %s%n", ERR_LOG_PATH));
}
try (Scanner s = new Scanner(p.getInputStream())) {
while (s.hasNextLine()) {
result.add(s.nextLine().trim());
}
}
return result;
}
That way you can tweak it more easily and keep your code cleaner. The script I used was:
#!/bin/bash
wmctrl -l | awk '{$1=""; $2=""; $3=""; print}'

Java and sudo command execution

I'm having a challenge with sudo invoked commands using both ProcessBuilder and Runtime.exec. I am thinking that ProcessBuilder is overall the better solution but both produce the same result - they execute shell commands fine on Ubuntu, but if I try to do a sudo -i mysql command for example:
public static void runProcess(String[] process) {
String s = null;
try {
Process p = new ProcessBuilder(process).start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null) { System.out.println(s); }
while ((s = stdError.readLine()) != null) { System.out.println(s); }
} catch (IOException e) { e.printStackTrace(); }
}
These 2 commands work:
String[] cmdArgs0 = { "sudo", "echo", "Done" };
runProcess(cmdArgs0);
String[] cmdArgs1 = { "bash", usbDrivePath+"/ASWebUI/Install.sh" };
runProcess(cmdArgs1);
But this does not:
String[] cmdArgs2 = { "sudo", "-i", "mysqldump", "Core", ">", cachePath+"/SQLDumps/Core.sql" };
runProcess(cmdArgs2);
Error:
mesg: ttyname failed: Inappropriate ioctl for device
mysqldump: Couldn't find table: ">"
ProcessBuilder doesn't allow you to redirect the output using > character. Instead you can use processBuilder.redirectOutput() method to specify the desired output.
File dumpFile = new File("Core.sql");
processBuilder.redirectOutput(Redirect.to(dumpFile));
Or even use --result-file option of mysqldump to specify the dump file:
mysqldump [options] --result-file=dump.sql

Run Shell Commands using Java provides problems

public class RunBashCommand {
public synchronized boolean RunInBash(String command) {
System.out.println("CMD: "+command);
/*String s; not working this code also
Process p;
try {
Process p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
PrintBufferReader(getError(p));
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}*/
try {
Process p = new ProcessBuilder("/bin/sh", command).start();
/*Process p = new ProcessBuilder("/bin/bash", command).start();*/
PrintBufferReader(getError(p));
/*p.destroy();*/
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
private static BufferedReader getOutput(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
private static BufferedReader getError(Process p) {
return new BufferedReader(new InputStreamReader(p.getErrorStream()));
}
private void PrintBufferReader(BufferedReader br) throws IOException {
int value = 0;
String s = "";
while((value = br.read()) != -1)
{
char c = (char)value;
s = s+c;
}
System.out.println("EEEE: "+s);
}
}
I tried this code, but it did not work.
following output came:
CMD: cd /home/jeevan/workspace/apb_proj/; source init.csh
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/; source init.csh: No such file or directory
CMD: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab
EEEE: /bin/sh: cd /home/jeevan/workspace/apb_proj/verif/compile/; make clean; make compile; make elab: No such file or directory
CMD: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh
EEEE: /bin/sh: sh /home/jeevan/workspace/apb_proj/verif/test_lib/src/apb_test31/runme.csh: No such file or directory
can some one help?
You're effectively running:
/bin/sh "cd /home/jeevan/workspace/apb_proj/; source init.csh"
When you run /bin/sh this way, it treats its first argument as the name of a file to execute as a shell script. Of course, there's no file named "cd /home/jeevan/workspace/apb_proj/; source init.csh", so you get an error message.
The correct way to invoke sh with a command as an argument is like this:
/bin/sh -c "cd /home/jeevan/workspace/apb_proj/; source init.csh"
Using process builder, you'd do:
Process p = new ProcessBuilder("/bin/sh", "-c", command).start();
The next problem that you're likely to run into is that it appears that the command you're trying to invoke is a csh command, not an sh command. "source" is a csh command, and the file you're trying to source is called "init.csh". So maybe you want to invoke csh instead of sh:
Process p = new ProcessBuilder("/bin/csh", "-c", command).start();
You need to split command arguments into separate parameters: not ProcessBuilder("bin/sh", "cd foo/bar") but ProcessBuilder("bin/sh", "cd", "foo/bar").
You can't use shell metacharacters (like ";") too. To run multiple commands, you have to start multiple processes.
Put all your commands into a List and pass it as the argument to the ProcessBuilder. As an alternative you can start the shell process, get it's OutputStream and write commands into this stream to execute them.

Executing Bash Script Returns Null In Java

I'm using UBUNTU/LINUX
I'm trying to build swing application for myself(this app need to work other platforms too) and i can not execute some commands on java.I tried to execute "java -version"
Here is my code:
Runtime run = Runtime.getRuntime();
Process p = run.exec("java -version");
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
for (String output = br.readLine(); output != null; output = br.readLine()) {
System.out.println(output);
}
} catch (IOException e) {
System.out.println(e);
}
It returns blank page no output!
However i can execute run.exec("ls") / or ("gedit") and so on... and I GET DATA
Also i can execute internal programs that in my computer.
Why i cant execute .sh files or built-in java commands and getting blank page?
You should use ProcessBuilder to mix standard and error outputs:
ProcessBuilder run = new ProcessBuilder("java", "-version");
run.redirectErrorStream(true);
Process p = run.start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
for (String output = br.readLine(); output != null; output = br.readLine()) {
System.out.println(output);
}
} catch (IOException e) {
System.out.println(e);
}
Check that java parent directory is in your PATH variable (output System.getenv("PATH")) or use a full path to the binary.
For script, use /bin/sh like that ProcessBuilder run = new ProcessBuilder("/bin/sh", "/path/to/your/script");
All path can be absolute starting with /, or relative (without /) to System.getProperty("user.dir").
The jvm itself directs output to the error stream
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {

Java to pass args to a Python script

NOTE: Path of python.exe has already been set
I am trying to create a Java program that passes the variable args (or any other variable) to a Python script.
import java.io.*;
public class PythonCallTest{
public static void main (String[] args){
String s = null;
Runtime r = Runtime.getRuntime();
try{
Process p = r.exec("cmd /c python ps.py+",args);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null){
System.out.println(s);
}
while ((s = stdError.readLine()) != null){
System.out.println(s);
}
System.exit(0);
}
catch(IOException ioe){
ioe.printStackTrace();
System.exit(-1);
}
}
}
The program compiles but when I run it with
java PythonCallTest sender-ip=10.10.10.10
I get the error
'python' is not recognized as an internal or external command, operable program or batch file.
How do I properly concatenate the string in r.exec("cmd /c python ps.py+",args)
EDIT
If I execute the following
Process p = r.exec("cmd /c python ps.py sender-ip=10.251.22.105");
Then the program works. The path for python.exe has already been set. I just need to know how to add args to r.exec, i.e how to concatenate cmd /c python ps.py with args
You are passing args as the second argument of Runtime.exec(...).
This overrides the default (inherited) environment of the new process to be useless, and hence the Path variable no longer contains the path to python.exe.
You need to use this version of Runtime.exec(...):
public Process exec(String[] cmdarray);
Which you would do so like this:
public static void main(String[] args) {
...
List<String> process_args = new ArrayList<String>(Arrays.asList("cmd", "/c", "python", "ps.py"));
process_args.addAll(Arrays.asList(args));
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec(process_args.toArray(new String[] {}));
...
} catch (IOException e) {
...
}
}

Categories