calling Python from Java - script not executed properly - java

I'm trying to execute a python script from a java program.
I have a weird problem, while the script is invoked but does not process completly.
to demonstrate this problem I've simplified the scenario to the following:
Java Code:
public class CallPython {
public static void main(String[] args) {
try {
Process p1 = Runtime.getRuntime().exec("python D://test.py narf");
int res1 = p1.waitFor();
System.out.println(res1);
Process p2 = Runtime.getRuntime().exec("python D://test.py narf2");
int res2 = p2.waitFor();
System.out.println(res2);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
Python Script:
import sys
a = sys.argv[1]
if (a == "narf"):
sys.exit(10)
file = open('bla.txt', 'w')
file.write("StackOverFlow is AWESOME!!!")
file.close()
sys.exit(5)
Running the script from the command line (with an argument different then "narf") results in creation of the file "bla.txt" while running the java code from eclipse prints:
10
5
and creates nothing...

Related

How make code to simulate the command < file.txt

I'm developing java code that needs to simulate the following:
my_command < file.txt
I tested writing to STDIN but it doesn't seem to be the solution.
Has someone already developed it?
Note, in the below code,
source is an instance of java.io.File
String commandLine = "myCommand";
Process process = Runtime.getRuntime().exec(commandLine);
new Thread(() -> {
try (BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
Scanner scanner = new Scanner(source)
){
String line;
while (scanner.hasNext()) {
line = scanner.nextLine();
stdin.write(line);
System.out.print(line);
}
stdin.flush();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
int ret = process.waitFor();
FYI my command is mysql
You should use class ProcessBuilder (rather than class Runtime).
I don't know what your my_command is, so the below code uses cleartool.
First I create the text file containing the cleartool subcommands that I wish to execute.
hostinfo
exit
(Note the empty last line of the file.)
I named this file exits_ct.txt
Now the java code that will run cleartool command, then enter the subcommands from the text file and print the command output to standard output.
import java.io.File;
import java.io.IOException;
public class PrcBldTs {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("cleartool");
pb.redirectInput(new File("exits_ct.txt"));
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
try {
Process proc = pb.start(); // throws java.io.IOException
int result = proc.waitFor(); // throws java.lang.InterruptedException
System.out.println("result: " + result);
}
catch (IOException | InterruptedException x) {
x.printStackTrace();
}
}
}
When I run the above code, I get the following output:
MY_COMP: ClearCase 9.0.0.0 (Windows NT 6.2 (build 9200) Pentium)
result: 0

From a java program, launch a Python script which listens for socket connections from said Java program

Im attempting to launch a python script from my Java program - The python script listens for socket connections from the Java program and responds with data.
In order to do this I have attempted to use the ProcessBuilder API to:
activate a python virtualenv (located in my working directory)
run my python script predictprobability.py such that it starts listening for connections from my java program.
this is what I have so far:
public class MLClassifierProcess{
//bash location //activate python venv //python interpreter //script
final String[] command_to_run = new String[] { "/bin/bash", "-c", "/env/bin/activate;", "/env/bin/python","predictprobability.py;" };
public void startML(){
ProcessBuilder builder = new ProcessBuilder(command_to_run);
Process pr = null;
try {
pr = builder.start();
} catch (IOException ioException) {
System.out.println("error");
}
}
public static void main(String[] args){
MLClassifierProcess p = new MLClassifierProcess();
p.startML();
}
}
however running the main function terminates straight away, when the script predictprobability.py should continue to run indefinitely.
I'm new to the ProcessBuilder API so any pointers on how to proceed would be greatly appreciated
If your Java program exits, the Python process you launched will exit as well as child processes are killed when a parent process dies unless they have been detached from that process.
If you want your Java program to keep running until the Python program has completed execution, then you need to have the Java code wait appropriately. Here's how to have it do so:
public class MLClassifierProcess{
//bash location //activate python venv //python interpreter //script
final String[] command_to_run = new String[] { "/bin/bash", "-c", "/env/bin/activate;", "/env/bin/python","predictprobability.py;" };
public Process startML(){
ProcessBuilder builder = new ProcessBuilder(command_to_run);
Process pr = null;
try {
pr = builder.start();
} catch (IOException ioException) {
System.out.println("error");
}
return pr;
}
public static void main(String[] args){
MLClassifierProcess p = new MLClassifierProcess();
Process pr = p.startML();
if (pr != null)
pr.waitFor();
}
}
In the end the solution was simple:
Process process = Runtime.getRuntime().exec("<path/to/venv/python_interpreter> "+"path/to/scripytorun.py)
In my case the succcessful command was
Process process = Runtime.getRuntime().exec( System.getProperty("user.dir")+"/env/bin/python "+System.getProperty("user.dir")+"/predictprobability.py");
process.waitFor();
#CryptoFool was right to point out that the absolute path to resources is needed, hence the System.getProperty("user.dir") prepended to the relative paths

executing a powershell command in eclipse

I am trying to run a powershell command in eclipse with the following code. The powershell script display the list of installed application on windows. The script works fine when it is executed in powershell. But I am unable to get the output on the console. Could someone please tell me what is the problem here?
import com.profesorfalken.jpowershell.PowerShell;
import com.profesorfalken.jpowershell.PowerShellNotAvailableException;
import com.profesorfalken.jpowershell.PowerShellResponse;
public class TestProcessList {
public static void main(String[] args) throws Exception {
try {
PowerShell powerShell = PowerShell.openSession();
String command = "Get-ItemProperty " +
"HKLM:/Software/Wow6432Node/Microsoft/Windows/CurrentVersion/Uninstall/* " +
"| Select-Object DisplayName, DisplayVersion, Publisher, InstallDate " +
"| Format-Table –AutoSize";
PowerShellResponse response = powerShell.executeCommand(command);
System.out.println("Proceses are:" + response.getCommandOutput());
powerShell.close();
} catch (PowerShellNotAvailableException ex) {
throw new RuntimeException("Failed to run PowerShell", ex);
}
}
}
Probably there are thrown some exceptions. Which in your case are not being re-thrown and are consumed (Bad practice).
Change tthe catch block to:
} catch (PowerShellNotAvailableException ex) {
throw new RuntimeException("Failed to run PowerShell", ex)
}
Then you will see what went wrong including its whole stacktrace and possible causes.
UPDATE:
You are actually using piped commands ("|" in execute command string) inside of single command. It wont't work as pipes are not easy to implement in java.
Try out solution basing on following example for command "ps aux | grep java":
import org.apache.commons.io.IOUtils;
public static void main(String[] args) throws Exception
{
Process p1 = Runtime.getRuntime().exec(new String[] { "ps", "aux" });
InputStream input = p1.getInputStream();
Process p2 = Runtime.getRuntime().exec(new String[] { "grep", "java" });
OutputStream output = p2.getOutputStream();
IOUtils.copy(input, output);
output.close(); // signals grep to finish
List<String> result = IOUtils.readLines(p2.getInputStream());
System.out.println(result);
}
Source: https://stackoverflow.com/a/7226858/1688570
As API of the PowerShell library is not known to me, you have to adapt the example to work with PowerShell library by yourself.
Code From PowerShell.java class.
int closingTime = 0;
while (!closeTask.isDone ()
&& !closeTask.isDone()) {
if (closingTime > MAX_WAIT) {
Logger.getLogger(PowerShell.class.getName()).log(Level.SEVERE, "Unexpected error when closing PowerShell: TIMEOUT!");
break;
}
Thread.sleep(WAIT_PAUSE);
closingTime += WAIT_PAUSE;
and
static final int WAIT_PAUSE = 10;
static final int MAX_WAIT = 2000;
This means your command takes more than 2000 milliseconds to close/complete.
I think adding a custom sleep in your code might help. I am not familiar with JPowerShell , you should take a look at PowerShell class. or try with TouDick's answer.
you have to add some wait time. I was executing some commands using java and was not able to print command output on console even though I was using response.getCommandOutput(). So, I tried below by adding wait:
PowerShellResponse response;
Map<String, String> maxWait = new HashMap<String, String>();
maxWait.put("maxWait", "300000");
PowerShell powerShell = PowerShell.openSession().configuration(maxWait);
response = powerShell.executeCommand(yourCommand);
System.out.println(response.getCommandOutput());
The wait time is to wait for maximum time.

execute julia scripts from Java

I'm coding Julia script with ZeroMQ.
My goal is to communicate with ZMQ between two scripts. Here is an example:
# script1
using ZMQ
ctx = ZMQ.Context()
sockDealer = ZMQ.Socket(ctx, DEALER)
ZMQ.set_identity(sockDealer, "idA")
ZMQ.connect(sockDealer, "tcp://localhost:5555")
ZMQ.send(sockDealer, "hello world!")
ZMQ.close(sockDealer)
ZMQ.close(ctx)
#script2
using ZMQ
function pollrecv(socket::ZMQ.Socket,zmsg::Message)
rc = -1
while true
rc = ccall((:zmq_msg_recv, ZMQ.zmq), Cint, (Ptr{Message}, Ptr{Void}, Cint),
&zmsg, socket.data, ZMQ.ZMQ_DONTWAIT)
if rc == -1
# Base.Libc.EAGAIN = 11
# Problem unsolved: Failure to find Base.Libc.EAGAIN
if !(ZMQ.zmq_errno() == 11)
throw(ZMQ.StateError(ZMQ.jl_zmq_error_str()))
end
return false
else
ZMQ.get_events(socket) != 0 && notify(socket)
break
end
end
return true
end
ctx = ZMQ.Context()
sockRouter = ZMQ.Socket(ctx, ROUTER)
ZMQ.bind(sockRouter, "tcp://*:5555")
fini = false
while !fini
println("listening...")
idSock = Message()
while pollrecv(sockRouter, idSock)
msg = ZMQ.recv(sockRouter)
println("msg recv: " * bytestring(msg))
fini = true
end
sleep(1)
end
ZMQ.close(sockRouter)
ZMQ.close(ctx)
I can execute them with Julia on the command prompt. Everything goes fine. Script 2 can receive the message of Script 1.
Now, I need to execute them from Java. Meaning that I need to create a java project which is just like a controller. Here is my Java project:
public class Container {
private Vector<String[]> commands;
public Container() {
this.commands = new Vector<String[]>();
}
public void addCommand(String[] strs) {
this.commands.addElement(strs);
}
public void execute() {
for(int i = 0; i < this.commands.size(); i++) {
try {
Process p = Runtime.getRuntime().exec(this.commands.get(i));
if(p.waitFor() != 0){
System.err.println("exit value = " + p.exitValue());
}
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while((line = in.readLine()) != null){
stringBuffer.append(line + "-");
}
System.out.println(stringBuffer.toString());
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch(InterruptedException e){
System.err.println(e);
}
}
}
}
//main
public class Main {
public static void main(String[] args) {
Container c = new Container();
String[] script1 = {"/usr/bin/julia", "/home/thomas/Julia/script1.jl"};
String[] script2 = {"/usr/bin/julia", "/home/thomas/Julia/script2.jl"};
c.addCommand(script1);
c.addCommand(script2);
c.execute();
}
}
However, when I run my java project, I can see that it keeps running but I can't see anything on the console: no result, no message, no error.
I think there is something wrong in my java project.
You'll want to run the two scripts concurrently: script2 is the server script, so it should be running when you run script1. As it is now, Process.waitFor() will wait for script1, the client script, to complete, before executing the server script script2 in the next for iteration.
You could start them as such:
String[] clientScript = { "/usr/bin/julia", "/home/thomas/Julia/script1.jl" };
String[] serverScript = { "/usr/bin/julia", "/home/thomas/Julia/script2.jl" };
Process server = Runtime.getRuntime().exec(serverScript);
Process client = Runtime.getRuntime().exec(clientScript);
and instantiate two threads to read their outputs:
(new ProcessReader(server)).start();
(new ProcessReader(client)).start();
using
public class ProcessReader extends Thread {
private Process p;
public ProcessReader(Process p) {
this.p = p;
}
#Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
try {
String line;
while ((line = in.readLine()) != null) {
System.out.println("Read: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Although, since the clientScript doesn't produce any output, you could just
start the scripts, and only read the output from the server script - no thread needed.
There's one more thing to consider: the serverScript must be listening... before the clientScript attempts to connect. So you may want to do this:
Process server = Runtime.getRuntime().exec(serverScript);
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
if ( in.readLine().equals("listening...") ) {
Process client = Runtime.getRuntime().exec(clientScript);
String line;
while ( (line=in.readLine()) != null )
System.out.println("Read: " + line );
}
Since this is not a specific answer to your question, this may help to you or other users that attempt to similar jobs.
JuliaCaller is an early stage library for calling Julia from Java. It executes the Julia executable as a Java process and runs a script in the Julia side. This script opens a TCP server that listens on a given port number. Every command, statement or expression sent from Java is then executed and results are sent back to Java in JSON format.
This library also implements the standard javax.script interface, that means, Julia libraries, functions, and programs can run like a scripting language that is implemented in Java (mimics).
Here is the example:
Constants.setProperties(Constants.JULIA_PATH, "/usr/local/bin/julia");
Constants.setProperties(Constants.JULIA_PORT, "8001");
// Creating a scripting interface for Julia
manager = new ScriptEngineManager();
engine = manager.getEngineByName("Julia");
// Sending command 'a = 3' to Julia from Java
engine.eval("a = 3");
// Handling the result in Java
Object a = engine.get("a");
More examples are given in the GitHub page.
Source code with Apache License

Not able to execute sort command using Runtime or ProcessBuilder

I am trying to execute this command sort --field-separator="," --key=2 /home/dummy/Desktop/sample.csv" -o /home/dummy/Desktop/sample_temp.csv using Java Runtime and ProcessBuilder.
Manually I am able to execute this command in linux, but using Runtime or ProcessBuilder, this command does not execute. It returns with an error code = 2.
Edit:
If I am trying to execute 'ls' command in linux through Java, I get the list of files in the current directory. But, If I try to execute the command 'ls | grep a', an IOException is thrown with error code=2.
Here is the snippet:
public static void main(String[] args) throws IOException {
InputStream is = null;
ByteArrayOutputStream baos = null;
ProcessBuilder pb = new ProcessBuilder("ls | grep a");
try {
Process prs = pb.start();
is = prs.getInputStream();
byte[] b = new byte[1024];
int size = 0;
baos = new ByteArrayOutputStream();
while((size = is.read(b)) != -1){
baos.write(b, 0, size);
}
System.out.println(new String(baos.toByteArray()));
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try {
if(is != null) is.close();
if(baos != null) baos.close();
} catch (Exception ex){}
}
}
There could be a range of issue with your code. Hence you did not supply your code I can only guess.
The output file needs to be already created
The ',' field separator does not need the quotes around it (see code below)
So after these 2 issues (both making the program exit with '2'), this code actually works:
import java.io.IOException;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder(Arrays.asList("sort", "--field-separator=,", "--key=2", "/tmp/sample.csv", "-o",
"/tmp/sample_temp.csv"));
Process p = pb.start();
int returnCode = p.waitFor();
System.out.println(returnCode);
}
}
Will print '0' and will sort the file correctly.
For the 'ls | grep' issue, read this great article: http://www.javaworld.com/article/2071275/core-javahen-runtime-exec---won-t/core-java/when-runtime-exec---won-t.html
The article basically explains that the Runtime.exec (and the ProcessBuilder wrapper) is for running processes and not a Shell (the ls | grep you are trying are actually 2 processes in Linux communicating with each other thru stdout/in).
I am able to execute that manually. And error code 2 means Misuse of Shell BuiltIns
I see in your example you are only invoking "ls", not "/usr/bin/ls" (or something like that).
When you execute manually you have the luxury of PATH environment variable which is not availabled to the process you create.
Use "which ls" to discover the location of 'ls' on your target system. For your code to be portable you will have to make it a configurable option.
this is the way to execute any bash commands like sort, ls, cat (with sub-options). Please find the snippet:
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec("script.sh");
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
In the exec() method, I passed a shell script which contains the bash command within it. That linux command will be executed and you can carry on with the next task. Hope this was helpful.

Categories

Resources