How to run python from java correctly? - java

I have next method:
public void callPython() throws IOException {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("python -c \"from test import read_and_show; read_and_show()\" src/main/python");
BufferedReader bfr = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedReader bfre = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
String outputStr = "";
while ((outputStr = bfr.readLine()) != null) {
System.out.println(outputStr);
}
while ((outputStr = bfre.readLine()) != null) {
System.out.println(outputStr);
}
}
in python file next code:
import os
from stat import *
def read_and_show():
print('worked!')
when i call this in terminal all worked correctly (before i cd to this directory):
MacBook-Pro-Nikita-2:python NG$ python -c "from test import read_and_show; read_and_show()"
worked!
when i run this code in my java code he return error:
File "<string>", line 1
"from
^
SyntaxError: EOL while scanning string literal
What i make wrong?
P.S.: i need run python method/class/file for read, parse and show graphical data. but for this need when java run python single method (def)

When executing other programs from java, I've found it's easier to keep it as simple as possible in java and instead execute a batch file
Runtime.getRuntime().exec("chrome.exe www.google.com");
Would instead become
Runtime.getRuntime().exec("openChrome.bat");
and openChrome.bat:
chrome.exe www.google.com
This makes it easier to test the command without recompiling, but may get complicated if you need to pass variables as arguments
To use shell built-ins like echo and cd, the batch file works wonders (ie echo test | program)
The major downside is you will have a floating .bat file next to your code
If packaging to a .jar, you may need to first copy the .bat file out of the .jar before executing

You're missing the shebang statement that states where the python interpreter is. It should be line #1
#!/usr/bin/python

Runtime.exec is obsolete. It was replaced by the ProcessBuilder class a long time ago:
ProcessBuilder builder = new ProcessBuilder(
"python", "-c", "from test import read_and_show; read_and_show()", "src/main/python");
builder.redirectInput(ProcessBuilder.Redirect.INHERIT);
Process pr = builder.start();
Notice that from test import read_and_show; read_and_show() does not have double-quote characters around it. Those quotes are something used by a shell (like bash). The python command never actually sees them, and shouldn’t see them. Executing a child process from Java (or any other language, really) does not invoke a shell; it executes the command directly. Which means the quotes wouldn’t be interpreted by any shell, and they’d be passed to the python program as part of the argument.

Related

Call from Java to run an executable as a different user

Question:
I have to call an exe file passing 2 string arguments. The call has to get executed as a different user
I referred few of the links that I got from hints. Couple of them were using powershell, few were using runas examples and so on.
But with powershell also, I am not sure if I will face the issue of "cannot be loaded because running scripts is disabled on this system".
Just because of this reason, I want to try something authentic.
Tried following approaches
Trying to do it through a call with RunAs command is making my life difficult. (called a batch file with RunAs command passing a separate pass.txt or savecred). savecred was ruled out by most people. Other one did not work as expected.
Powershell, has issues wherein, I always get a userid/password popup, even though I run through a Java file.
I also get an error in the command prompt as here below
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodExcept
ion
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
(Sample code attached below)
public class SamplePS {
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
String command = "powershell C:\\Users\\Ramu\\Project\\SampleFile.ps1";
//String cmds[] = {"C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe", "\\c", "SampleFile.ps"};
System.out.println("1");
Process proc = runtime.exec(command);
InputStream is = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
System.out.println("2");
}
}
My ps1 file is as here below
$credential = New-Object System.Management.Automation.PSCredential <<domain>>\<<user id>>, <<password>>
start-process cmd.exe -arg "/k dir" -Credential $credential
What is the best way to handle this scenario?
Please suggest! I am not sure what approach to take.
Powershell or Perl or any other scripting.
Whatever it be, I have to make a call from Java file.
Please suggest!
Note: For time being, I dont mind the password being sent as a plain text.
The exe file is in Windows machine
Thanks!
Ram

How to perform java command prompt action on unix

I have two jar files named test1.jar and test2.jar.
In order to execute a function in in this jar file, I run below command in cmd.
“java getOutput argument1 argument2 argument3 argument4”
As a pre-requisite, I have set the following entries in my system environment variables to execute the java function using the above command.
1.CLASSPATH=C:\Folder\test1.jar;C:\Folder\test2.jar;C:\Program Files\Java\jre1.8.0_181\lib\plugin.jar
2.JAVA_BIN=C:\Program Files\Java\jre1.8.0_181\bin
3.JAVA_HOME=C:\Program Files\Java\jre1.8.0_181
4.PATH = C:\Program Files\Java\jre1.8.0_181\bin
The output of the above command is a string.
I have another java code. I have to capture the above string output in a variable in my java program and I am able to do this by using below java code in eclipse.
String strArgs= strArg1+" "+strArg2+" "+strArg3+" "+strArg4;
Process p=Runtime.getRuntime().exec("cmd /c java getOutput "+strArgs+"");
BufferedReader input =new BufferedReader(new
InputStreamReader(p.getInputStream()));
String strOutput = input.readLine();
if (strOutput != null) {
System.out.println(strOutput);
String strVariable = strOutput;
input.close();
}else {
System.out.println("FAIL- Output not generated");
}
In order to execute the above code on unix, I replace Line 2 with "Process p=Runtime.getRuntime().exec("usr/bin/java getOutput "+strArgs+"");" , convert the eclipse java project into a jar file named automation.jar. And I try to execute this jar file on unix using the below command .
`java -cp automation.jar Package.MainClass.'
When I run the code I get the output as null. But when I run the command on windows command prompt I get the output string.
Could you please help me on how to set the system variables in unix and perform the above operation to generate the string output.
Please let me know if any additional information required.
cmd is windows only. Unix uses a shell. But you shouldn't need either here. Just remove the cmd call.
Process p = Runtime.getRuntime().exec("java getOutput " + strArgs);
If it can't find Java, you can read the JAVA_BIN (or JAVA_HOME) from the environment.
String java_bin = System.getenv("JAVA_BIN");
Process p = Runtime.getRuntime().exec(java_bin + "/java getOutput " + strArgs);
Finally, your environment variables look like Windows path variables. Make sure they're correct for your Unix environment (Unix doesn't have a "C" drive).

complete CMD command not running from java

I am running the below query through Java on a Postgres DB using psql:
psql.exe -U <user> -w -h <host> -d <db_name> -a -f <file> 2> "<path_to_file>\psql.log"
Initially, for quite some time the java program did create the file. Then I ran into another problem, that it was not overwriting the log file. So i used file.delete() function after every time this log file got created via java.
Now, Java is not even creating the log file for some reason. If I run the above manually in command prompt, it runs absolutely fine, but not via java code. I can see this command getting run in the java log, but it does not create the log file even when i have removed the file.delete() function
I researched a lot on it but could not find any solution. Any help would be highly appreciated.
its a long code..so i will tell you the relevant part.
I am calling a function from a thread. Code is below for that function:
public static void SaveACopyfileToServer(int auditid,String filepath,String fname,String tb_name,String plpgsql_path) throws Exception
{
Map<String, String> env = System.getenv();
String plpgsql = "\""+plpgsql_path+"\" -U "+env.get("PG_USER")+" -w -h "+env.get("PG_HOST")+" -d "+env.get("PG_DB")+" -a -f "+"\""+filepath+"copy_"+tb_name+auditid+".sql\" 2> \"C:\\ER\\ETL\\logs\\psql.log\"";
System.out.println(plpgsql);
Process p = Runtime.getRuntime().exec(plpgsql);
p.getOutputStream().close();
p.waitFor();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
Calendar cal10 = Calendar.getInstance();
System.out.println("Data loaded for "+tb_name+auditid+" at "+sdf.format(cal10.getTime()));
}
After this i am calling another function which is:
public static void extracterrorreason(String fname,int auditid,String sessionid,Connection con_pg) throws FileNotFoundException, IOException, InterruptedException{
File file = new File("C:\\ER\\ETL\\logs\\psql.log");
if(file.exists())
{
System.out.println("File present");
}
else
{
System.out.println(file+" not found");
}
if (file.length()!=0){
System.out.println("Log file being read is "+file);
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
String out_err = line.substring(line.indexOf("ERROR"));
System.out.println(out_err);
System.out.println("Error while loading the file into Database for file "+fname);
String comment = "CopyToStage','"+out_err;
Utils.updateAuditDetailTable(auditid, sessionid, -1, comment, true, con_pg,"");
br.close();
//file.delete();
}
}
The first function used to create the psql.log file, but now it does not even create it. Not sure where is the problem. Every time i run the code and from the second function,i get the printline that log file not found. The part before the redirection of the output of the cmd command works fine.
I tried process builder also..
I even tried it with Process builder
String plpgsql = "\""+plpgsql_path+"\" -U "+env.get("PG_USER")+" -w -h "+env.get("PG_HOST")+" -d "+env.get("PG_DB")+" -a -f "+"\""+filepath+"copy_"+tb_name+auditid+".sql\" 2> \"C:\\ER\\ETL\\psql_" +auditid +".log\"";
ProcessBuilder pb = new ProcessBuilder("cmd.exe",plpgsql);
Process p =pb.start();
p.getOutputStream().close();
p.waitFor();
I expect that the problem is that Runtime.getRuntime().exec(plpgsql) is splitting the command line into arguments incorrectly. Basically, exec does not understand quoting. Instead, it splits wherever it sees one or more spaces ... even if those spaces are in quotes.
The solution is to use the exec(String[]) overload, and pass each individual argument as a separate string; e.g.
.exec(new String[]{plpgsql_path,
"-U",
env.get("PG_USER"),
"-w,
"-h",
// etcetera
});
UPDATE
I didn't notice that you were using > output redirection as well1.
That doesn't work with exec either. (And the same applies to all shell syntax.) To get redirection, you need to use ProcessBuilder and one of the redirect methods.
The other alternative is to run the command in a shell. Pass the command as a string, and let the shell take care of the quote handling, substitution of environment variables, globbing, redirection ... and so on.
For example (if you were running on UNIX, Linux or MacOSX):
.exec(new String[]{"/bin/sh", "-c", plpgsql});
For Windows
.exec(new String[]{"cmd.exe", "/C", plpgsql});
Note the "/C" option in the Windows case!
1 - It serves you right for not line-breaking that ~200 character line in your source code! Check out what Java coding standards say about source line lengths ...

Getting error in calling shell script in windows environment using java code and cygwin...!

I want to call shell script on windows environment using java code.
I am trying to execute code below to run my test script(not actual script):
Java Code:
public static void main (String args[]) {
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec("C:\\cygwin\\bin\\bash -c '/cygdrive/d/scripts/test.sh'");
InputStream in = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
System.out.println("OUT:");
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
in = p.getErrorStream();
br = new BufferedReader(new InputStreamReader(in));
System.out.println("ERR:");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
test.sh
#!/bin/bash
rm -rf ./test
But I am getting these error and script in not able to remove the directory.
ERR:
/cygdrive/d/ereader/scripts/test.sh: line 2: $'\r': command not found
/cygdrive/d/ereader/scripts/test.sh: line 3: rm: command not found
Another thing, when I run the script from the cygwin terminal it works fine. I checked the path variable they all are fine. But I try to execute same script through java code it gives error..
Now how to tell java program where to refer for rm commands?
The giveaway is the '\r' error.
Windows and Unix (which includes Mac and Linux) use different representations of a new line. Windows uses '\r\n' while Unix simply uses '\n'. Most programming editors account for this and only insert a '\n' so they work with Unix tools.
I would suggest retyping your shell script in another editor like Notepad++ (which only inserts '\n'), or make sure your current editor is set to use Unix newlines. You have to retype it or the bad '\r\n' sequences will get copied over. You might have some luck in doing a replace-all but that always acts flaky for me.
probably you will need to set the PATH variable first thing in the test.sh script. Make sure rm is in the PATH you set
Not really answer. You could try following to narrow down the problem
Use ProcessBuilder instead of Process. It is much more friendly to handle arguments.
Set absolute path to rm (/bin/rm ) in the script
remove using absolute path to directory or remove after verifying you are in the correct directory..
The bash prompt you have is result of cygwin.bat calling bash with --login. It will have path variables and other usesul stuff sources. bash -c does not do it.
Try launching bash.exe with bash -l -c <command> : This sources the bash profile.

How do I execute an executable file from within a java file on linux?

I am trying to execute an executable file and a perl script from within a java program. I have found many topics similar to this but most of them refer to windows. I know java is platform independent and it should work anyways but it doesn't. The solution I have tried already is the one based on the java Runtime and it's exec method. It works just fine on windows but since I'm porting my program on linux I need to adapt it. As I said I need to execute an executable file that I have compiled and was written in c++ which it looks like it's working but it finishes executing with an exit value of 1. I have no idea what it means but on windows it exits with 0 and that's how it should be on linux as well (?!?!). The pearl script on the other hand does not start at all. I use the command "perl script.pl" and it exits with a value of 255. Needless to say, it doesn't do what it's supposed to.
Does anybody know another way to execute these files? Or maybe where I am wrong with my implementation?
here's the code if you want to take a look at it:
This is the one for the perl script
public static void main(String[] args){
System.out.println("Starting");
try{
String[] cmd = {"perl", "cloc-1.53.pl"};
Process pr = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line=null;
while((line=input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exit code: " + exitVal);
} catch (Throwable t){
t.printStackTrace();
}
}
For the compiled file I change this:
String[] cmd = {"perl", "cloc-1.53.pl"};
with:
String cmd = "./UCC";
There should be no differece in starting processes on windows and linux.
Good article http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
Its for the old way but gives good insight.
Article converting to the new way:
From Runtime.exec() to ProcessBuilder

Categories

Resources