Some context: I'm trying to make a GUI on java and have python code run once I click a button on the GUI. For example if I press start on the java GUI, it will run the python code on file .py.
Why is it not outputting anything? You can also try this by creating a test python file and just inputting your own file location into the code below.
Code so far:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.swing.JFrame;
public class main_gui extends JFrame {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder("cmd.exe",
"cd \"G:\\...Javaa\\filetranslatorapplication\\file_translator_app.py");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) {
break;
}
System.out.println(line);
}
}
}
Two things to keep in mind:
The python file in NOT in the same place as this java file.
The java file and python file are both on a usb, hence the "G:\..".
Also, if anyone has a better way of running python code through java gui, please feel free to point me in the right direction.
The following should work for you:
ProcessBuilder builder = new ProcessBuilder("cmd",
"/c \"G: && python Javaa\\filetranslatorapplication\\file_translator_app.py\"");
This gets executed when I run my Java application from a different drive. But, for you, if it is the same drive, need not switch to G:. You may execute the py file with python command.
Your process simply does not make sense.
It simply spawn a cmd, and cd to an invalid directory (as it is a file).
What you want is probably
cmd /c python g:\your\path\foo.py
or
cmd /c g:\your\path\foo.py
or simply
may\be\full\path\is\needed\python g:\your\path\foo.py
So, your code should look like:
ProcessBuilder builder
= new ProcessBuilder("cmd.exe", "/c", "python", "g:\\yourpath\\file_translator_app.py");
// or
// = new ProcessBuilder("python", "g:\\yourpath\\file_translator_app.py");
// or
// = new ProcessBuilder("cmd", "/c", "g:\\yourpath\\file_translator_app.py");
Related
I am new to both Java and Linux, I was trying to use some Runtime.exec() commands that would allow my program to execute commands in Linux such as "cd /mnt/" and "ls --group-directories-first" to list files and directories contained in /mnt/ but I think I am making a problem with the execution.
I tried my code to only include the "ls --group-directories-first" and it worked like a charm, only problem was, it only listed subdirectories and files in the projects folder. I wanted to make my program go to /mnt/ first so I made my command line to a command array by using exec(String[] cmdarray) format as process1 = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"}); and when I ran it on linux, it just got executed without any printed runtime errors but also without any feedback/printed lines.
Here is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec("ls --group-directories-first");
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());
p.destroy();
} catch (Exception e) {}
}
}
This worked and printed out:
"line: DummyFolder1
line: linCom.class
line: linCom.java
exit: 0"
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"});
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());
p.destroy();
} catch (Exception e) {}
}
}
This just got executed with no printed lines.
I expected my program to just go to the /mnt/ directory and print out subdirectories and files on there, but it just got executed with no visible runtime errors and no printed lines.
I have looked at other entries but could not find any answer to my problem.
EDIT: I changed "no errors" with "no error messages" to make it clear that if program had any errors, I did not get any feedback about it.
Here's where the UNIX process model can be confusing.
What you have tries to run the program named cd /mnt/ with the first parameter of ls --group-directories-first . Unix programs can be named anything (they're just filenames) but there's no program named cd /mnt. And anyway, the cd operation is actually performed by a shell, not as a forked/execed program.
You hope to run this shell command from your Java program: cd /mnt/; ls --group-directories-first . The trouble is, Java's .exec() method does not give you a shell, so shell commands don't work.
You can try this instead. It's like running the shell command
/bin/sh -c "cd /mnt/; ls --group-directories-first"
With this, you start a shell, then tell it to run -cthe command you want.
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh",
"-c",
"cd /mnt/; ls --group-directories-first"});
But it's quite dependent on the machine where your Java program runs, so be careful.
Reference: How to invoke a Linux shell command from Java
Do not use an external process just to list files. Java has plenty of ways to do that. All of them are in the Files class. For example:
Path dir = Paths.get("/mnt");
try (Stream<Path> files = Files.list(dir).sorted(
Comparator.comparing((Path p) -> !Files.isDirectory(p))
.thenComparing(Comparator.naturalOrder()))) {
files.forEach(System.out::println);
}
Do you really need to use Runtime.exec()comands? That would make your code platafform dependent.
You could use File.listFiles():
File folder = new File("/mnt");
for (File f : folder.listFiles()) {
System.out.println(f.getName());
}
That would make the code less plataform dependent
I am trying to use this command:
git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
Which I am running through ProcessBuilder. Now, I know that the rest of my code works, as I have tested it with other examples. But I am not sure how to split this command so that it works for ProcessBuilder.
Apparently, this method did not work:
String[] command = {"git", "checkout", "`git rev-list -n 1 --before=\"2014-01-01 12:00\" master`"};
This did not work as well:
String[] command = {"git", "checkout", "`git", "rev-list", "-n", "1", "--before=\"2014-01-01 12:00\"", "master`"};
I am also not getting any output from the console (I do InputStream), which means it's harder for me to figure out what's the issue. I am thinking the problem should be obvious to people familiar enough with ProcessBuilders, so yeah...
The rest of my code looks as such:
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.directory(new File(fullPath));
process = processBuilder.start();
And the path for the directory should be correct as I checked it (it is inside of the main directory of the repository).
If by any chance I need to provide other parts of the code, I will.
The back-ticks are actually handled by the unix shell - Java doesn't process them. When using process builder you should execute the command given in the back-ticks and pass the output as parameters to the second command. A simple example is below: (using 'ls').
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
public class ProcessBuilderTest {
public static void main(String[] args) throws IOException, InterruptedException {
// Command: ls `ls /etc/passwd /etc/services`
// Read the output from the command second ls...
ProcessBuilder pb = new ProcessBuilder("ls", "/etc/passwd", "/etc/services");
Process process = pb.start();
InputStream is = process.getInputStream();
List<String> lines = IOUtils.readLines(is, Charset.defaultCharset());
ArrayList<String> cmdParts = new ArrayList<>();
cmdParts.add("ls");
cmdParts.addAll(lines);
// Construct the second command
ProcessBuilder pbLs = new ProcessBuilder(cmdParts);
Process lsProcess = pbLs.start();
System.out.println(IOUtils.readLines(lsProcess.getInputStream(), Charset.defaultCharset()));
lsProcess.waitFor();
}
}
I'm using a Raspberry Pi to receive the UID of some RFID cards from a RC522 reader. The python script I'm running is here: https://github.com/mxgxw/MFRC522-python
For various reasons I won't go into, I have to process these IDs in Java.
It seems the most viable solution is to run the python script and read in the result into Java. The problem is, the Python code gives continuous output, i.e. it will print the ID of the card into the console window as and when a card is tapped onto the reader, and will only terminate on a user's command.
I'm currently using a ProcessBuilder to execute the script, however it seems like it's more suited to run the program and read in the immediate result back to Java (which of course is null if I haven't tapped a card onto the reader). I've tried executing the code in a while(true) loop to continuously start the process - but this doesn't work:
import java.io.*;
public class PythonCaller {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// set up the command and parameter
String pythonScriptPath = "/home/pi/MFRC522-python/Read.py";
String[] cmd = new String[3];
cmd[0] = "sudo";
cmd[1] = "python"; // check version of installed python: python -V
cmd[2] = pythonScriptPath;
// create runtime to execute external command
ProcessBuilder pb = new ProcessBuilder(cmd);
// retrieve output from python script
pb.redirectError();
while(true){
Process p = pb.start();
System.out.println("Process Started...");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : "+ret);
}
}
}
The output on the console window is blank - no exceptions thrown or println's.
Any help would be massively appreciated!!
Thanks
EDIT - I've surrounded my code in a try/catch to see if there's anything at all being thrown, and it doesn't seem to be the case
I use the following programs to try to reproduce the problem
PythonCaller.java
import java.io.*;
public class PythonCaller {
public static void main(String[] args) throws IOException {
// set up the command and parameter
String pythonScriptPath = "/home/pi/test.py";
String[] cmd = { "python", pythonScriptPath };
// create runtime to execute external command
ProcessBuilder pb = new ProcessBuilder(cmd);
// retrieve output from python script
pb.redirectError();
while(true){
Process p = pb.start();
System.out.println("Process Started...");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : "+ret);
}
}
}
test.py
uid =(123,456,789,999)
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
The method pb.redirectError() doesn't modify anything. It returns a value, your codes does nothing with it. (see http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#redirectError%28%29). What you want is probably redirectErrorStream(boolean redirectErrorStream)
The second line of the python test program is taken directly from "Read.py" (line 44). It causes an error with the java intValue() method. If I replace it with String ret = in.readLine();, the program seems to work.
Since the Process p = pb.start(); is inside the loop, the python subprogram is called repeatedly.
The next step should be to try running the python program manually in a console, see what it does.
(n.b. I had to remove "sudo" and change paths to be able to test on my system, you should have no problems replacing things for your setup).
I've managed to get around it by editing my Python script - it returns null if there's no card on the reader, and the UID if there is.
I'll probably use observer pattern or similar on the Java end to detect when there's a card. Very resource intensive but it'll have to do for now!
I'm trying to run a shell script (say myscript.sh) from a java program.
when i run the script from terminal, like this :
./myscript.sh
it works fine.
But when i call it from the java program, with the following code :
try
{
ProcessBuilder pb = new ProcessBuilder("/bin/bash","./myScript.sh",someParam);
pb.environment().put("PATH", "OtherPath");
Process p = pb.start();
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
String line ;
while((line = br.readLine()) != null)
System.out.println(line);
int exitVal = p.waitFor();
}catch(Exception e)
{ e.printStackTrace(); }
}
It doesnt goes the same way.
Several shell commands (like sed, awk and similar commands) get skipped and donot give any output at all.
Question : Is there some way to launch this script in a new terminal using java.
PS : i've found that "gnome-terminal" command launches a new terminal in shell,
But, i'm unable to figure out, how to use the same in a java code.
i'm quite new to using shell scripting. Please help
Thanks in advance
In java:
import java.lang.Runtime;
class CLI {
public static void main(String args[]) {
String command[] = {"/bin/sh", "-c",
"gnome-terminal --execute ./myscript.sh"};
Runtime rt = Runtime.getRuntime();
try {
rt.exec(command);
} catch(Exception ex) {
// handle ex
}
}
}
And the contents of the script are:
#!/bin/bash
echo 'hello!'
bash
Notes:
You'll do this in a background thread or a worker
The last command, in the shell script, is bash; otherwise execution completes and the terminal is closed.
The shell script is located in the same path as the calling Java class.
Don't overrwrite your entire PATH...
pb.environment().put("PATH", "OtherPath"); // This drops the existing PATH... ouch.
Try this instead
pb.environment().put("PATH", "OtherPath:" + pb.environment().get("PATH"));
Or, use the full directories to your commands in your script file.
You must set your shell script file as executable first and then add the below code,
shellScriptFile.setExecutable(true);
//Running sh file
Process exec = Runtime.getRuntime().exec(PATH_OF_PARENT_FOLDER_OF_SHELL_SCRIPT_FILE+File.separator+shellScriptFile.getName());
byte []buf = new byte[300];
InputStream errorStream = exec.getErrorStream();
errorStream.read(buf);
logger.debug(new String(buf));
int waitFor = exec.waitFor();
if(waitFor==0) {
System.out.println("Shell script executed properly");
}
This worked for me on Ubuntu and Java 8
Process pr =new ProcessBuilder("gnome-terminal", "-e",
"./progrm").directory(new File("/directory/for/the/program/to/be/executed/from")).start();
The previous code creates a new terminal in a specificied directory and executes a command
script.sh Must have executable permissions
public class ShellFileInNewTerminalFromJava {
public static void main(String[] arg) {
try{
Process pr =new ProcessBuilder("gnome-terminal", "-e", "pathToScript/script.sh").start();
}catch(Exception e){
e.printStackTrace();
}
}
}
hi im trying to do a program that will be able to access command prompt and be able to start solr's start.jar file so my search program could work..the problem is when im using the codes in eclipse, the program runs smoothly but when i transfered my program in netbeans it says that it cannot access the jar file.it doesnt give me any stack trace error that is why i dont know what is wrong..here is my code
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class CmdTest {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder(
"cmd.exe", "/c", "cd \"D:\\Downloads\\solr-4.2.1\\solr-4.2.1\\example\" && java -jar start.jar");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
}
the error is just plainly like this : Error:Unable to access jarfile start.jar
I can think of a few things to start with...
Each parameter you past to the ProcessBuilder is expected to be a separate argument for the command to be executed. Fine, I'm not 100% if the command you've constructed will work, but it just looks like a mess to me.
Instead, if you want to change the location that the command is executed in, why not just use the directory method of ProcessBuilder, which will change the execution context to the specified location when the command is executed...
public class CmdTest {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder("java.exe", "-jar", "start.jar");
builder.directory(new File("D:\\Downloads\\solr-4.2.1\\solr-4.2.1\\example"));
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = r.readLine()) != null) {
System.out.println(line);
}
}
}