How can I invoke a Java program from Perl? - java

I'm new with Perl and I'm trying to do something and can't find the answer.
I created a Java project that contains a main class that gets several input parameters.
I want to wrap my Java with Perl: I want to create a Perl script that gets the input parameters, and then passes them to the Java program, and runs it.
For example:
If my main is called mymain, and I call it like this: mymain 3 4 hi (3, 4 and hi are the input parameters), I want to create a Perl program called myperl which when it is invoked as myperl 3 4 hi will pass the arguments to the Java program and run it.
How can I do that?

Running a Java program is just like running any other external program.
Your question has two parts :
How do I get the arguments from Perl to the Java program?
How do I run the program in Perl?
For (1) you can do something like
my $javaArgs = " -cp /path/to/classpath -Xmx256";
my $className = myJavaMainClass;
my $javaCmd = "java ". $javaArgs ." " . $className . " " . join(' ', #ARGV);
Notice the join() function - it will put all your arguments to the Perl program and separate them with space.
For (2) you can follow #AurA 's answer.
Using the system() function
my $ret = system("$javaCmd");
This will not capture (i.e. put in the variable $ret) the output of your command, just the return code, like 0 for success.
Using backticks
my $out = `$javaCmd`;
This will populate $out with the whole output of the Java program ( you may not want this ).
Using pipes
open(FILE, "-|", "$javaCmd");
my #out = <FILE>
This is more complicated but allows more operations on the output.
For more information on this see perldoc -f open.

$javaoutput = `java javaprogram`;
or
system "java javaprogram";
For a jar file
$javaoutput = `java -jar filename.jar`;
or
system "java -jar filename.jar";

Related

Is there a way to have Java call a bash script which calls javac and java?

I'm trying to train a neural network to play Halite 3. The provided interface is a bash script which:
1. compiles my bot
2. calls the binary file with a string to run the bot java myBot
I'm trying to run this script from Java to train the network.
I've tried using a ProcessBuilder to run the script as well as the binary in the script. Running the script produces no output, and using echo I've determined that the program terminates when javac is called in the script. Removing that call, it terminates when the program is run.
I've tried calling the program directly as well using ProcessBuilder, and this does indeed produce output. The issue is it doesn't run the bots properly saying it can't find the file. I've tried changing the path to be relative to different directory levels as well as the absolute path (the java command doesn't seem to like absolute paths?).
Calling the binary directly:
List<String> cmd = new ArrayList<>();
cmd.add(dir+ "/src/halite");
// Replay
cmd.add("--replay-directory");
cmd.add(dir+"/replays/");
// Options
cmd.add("--results-as-json");
cmd.add("--no-logs");
// Dimensions
cmd.add("--width");
cmd.add("16");
cmd.add("--height");
cmd.add("16");
// Players
cmd.add("\"java -cp . myBot\"");
cmd.add("\"java -cp . myBot\"");
Process proc = new ProcessBuilder(cmd).start();
InputStream is = proc.getInputStream();
Scanner s = new Scanner(is);
while (s.hasNext()){
System.out.println((String) s.next());
}
This code does produce a JSON, however, I get an error in my logs saying that the bots do not run.

Python 2.7 subprocess call method not working to run java command

I am trying to use a python script to manipulate the input files for my java program. The way I am doing it is I am generating the file name and passing it to subprocess.call() method to execute. Here is my program:
def execJava(self):
self.thisCmd="pause"
call(self.javaCmd,shell=True)
call(self.pauseCmd,shell=True)
Where,
self.javaCmd = 'java -ea -esa -Xfuture -Xss64m -classpath "C:\FVSDK_9_1_1\lib\x86_64\msc_12.0-sse2_crtdll\*" -Djava.library.path="C:\FVSDK_9_1_1\lib\x86_64\msc_12.0-sse2_crtdll;C:\FVSDK_9_1_1\lib\x86_64\share" com.cognitec.jfrsdk.examples.MatchFIRAgainstGallery C:\FVSDK_9_1_1\etc\frsdk.cfg 0 .\tmp\frsdk-scratch\probe_1.fir .\tmp\test\*'
Yes, it's a long complex java instruction but when I run it in the command prompt it works fine. Only when I pass it as a string it doesn't run and returns:
Exception in thread "main" java.lang.Error
After some exploration into the problem, I have discovered that it is due to \x, \t in the instruction, so it is executing
.\tmp\test\*
as
mp est\*
as it replaces \t with tab space while executing. I have looked up quite a bit and didn't find any solution. Any help is much appreciated.
Use forward slashes "/" instead of back slashes "\" for your paths.

how to pass parameter to shell script to use as part of variable filename [duplicate]

This question already has answers here:
How do I parse command line arguments in Bash?
(40 answers)
Closed 4 years ago.
I am trying to programmatically call from my java program a shell script that in turn executes a command depending of the parameter sent.
the command to be executed inside the connectvpn.sh shell script is:
echo myrootpassword | sudo -S /usr/local/Cellar/openvpn/2.3.8/sbin/openvpn --config /usr/local/etc/openvpn/1.opvn
or
echo myrootpassword | sudo -S /usr/local/Cellar/openvpn/2.3.8/sbin/openvpn --config /usr/local/etc/openvpn/2.opvn
and so on from a long list, where the filename number I want to be variable depending on the value of the parameter received
So I want my java program to be able to use always the same shell script but use different .ovpn file depending on the parameter sent.
I believe that on my java program I have to call it something like this:
server_number = 1;
ProcessBuilder pb = new ProcessBuilder("./connectvpn.sh", server_number);
Process proc = pb.start();
What would go in the shell script so that the filename called is variable and for the example shown it uses 1 but other times it uses whatever number is sent as parameter?
Thank you very much!
In the shell script, use $1 to denote the first parameter passed to it.
Fix your java as below,
ProcessBuilder pb = new ProcessBuilder("./connectvpn.sh", String.valueOf(server_number));

Passing pre-escaped command-line arguments to ProcessBuilder

I bumped into this problem today when setting up a local set of communicating programs. Basically one of my applications is sending some data to another, and part of this data is a string containing a command to execute (like you would from the command-line). Let's say, for example:
g++ foo.cc bar.cc -o foobar
is the command sent by my first application. The second application, which receives the command (amongst other things), needs to execute this command after doing some other processing.
Now, at first I thought this would be trivial using a ProcessBuilder:
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
ProcessBuilder builder = new ProcessBuilder(exampleCommand);
builder.start().waitFor();
However this is where the problem occurs.
CreateProcess error=2, The system cannot find the file specified
Okay, no worries I guess I can't just dump the whole thing into the builder. The first part of the command is usually a trivial string so I thought I could probably get away with a split around the first ' ' to separate the program name and arguments.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
String[] parts = exampleCommand.split(" ", 2);
ProcessBuilder builder = new ProcessBuilder(parts[0], parts[1]);
builder.start().waitFor();
And this brought me a little closer, the g++ file could now be found correctly, however after examining the stderr of g++ I found that the following error had occurred:
g++.exe: error: foo.cc bar.cc -o foobar: No such file or directory
At this point I realised that the ProcessBuilder class must be escaping all arguments passed to it in preparation for the command-line (hence the reason it usually takes arguments as an array of individual arguments rather than just a predefined argument string).
My question is, "Is there any way to pass a raw string of arguments to a ProcessBuilder and say THERE, execute EXACTLY this?"
Because the command comes from another application and is in no way static I can't just break the arguments down into an array beforehand and pass them to the ProcessBuilder constructor properly. The arguments are not so trivial that simply splitting the string around a ' ' will work properly either; arguments might contain spaces escaped with double quotes. For example:
g++ "..\my documents\foo.cpp" bar.cpp -o foobar
Could be a command coming from the application and splitting that string around ' ' and passing it to the ProcessBuilder will result in corrupt arguments.
If there is no proper way to do this can someone please point me to a standalone command line argument parser (in Java) that can turn a command-line string into a valid String[]?
Okay I feel rather foolish now but I achieved my desired result by simply reverting back to the good old Runtime.getRuntime().exec(...). I'll leave the question up in case anyone is as silly as me and find it useful.
String exampleCommand = "g++ foo.cc bar.cc -o foobar";
Runtime sys = Runtime.getRuntime();
sys.exec(exampleCommand);
Easy.
A comment to the Runtime.getRuntime().exec(...) solution:
The Runtime.getRuntime().exec(...) is not good anymore. In java executed on OSX El Capitan, 'Runtime.getRuntime().exec(...)' contains an error that sometimes closes the opened process when the java program exits. It works fine on previous OSX versions. However, ProcessBuilder works on all OSX versions.
(Haven't posted enough to have a enough rep points to make this as a normal comment.)

Java executing Linux commands

I want to write a java code that executes some Linux command:
String cmd = "cd /home/arps/FBI" ;
Process p=Runtime.getRuntime().exec(cmd);
String [] arr = new String [9] ;
arr[0] = "cd /home/arps/FBI" ;
for(int n = 1 ; n < 9 ; n++){
String command = "mv" + " " + "/home/arps/FBI/hr" + n + ".txt" + " " + "/home/arps/FBI/hrs" + n +".txt" ;
arr[n] = command ;
}
Process pp=Runtime.getRuntime().exec(arr);
In above code: I try to rename 8 files named hr1, hr2 .... to hrs1 , hrs2 ... etc. In cd command I try to enter the required directory. However, I have used absolute path also. But the code is giving error:
java.io.IOException: Cannot run program "cd": java.io.IOException: error=2, No such file or directory
java.io.IOException: Cannot run program "mv /home/arps/FBI/hr1.txt /home/arps/FBI/hrs1.txt": java.io.IOException: error=2, No such file or directory
Can anybody help me why is this happening though I manually execute those command means "mv /home/arps/FBI/hr1.txt /home/arps/FBI/hrs1.txt" and executes properly?
cd is a built-in command to the current shell - you can't execute it - it's a shell built-in, as the cwd is a process-level setting, so a new process has it's own value. There is no way to change the cwd from within the java process.
The array argument version of exec is for executing a single command, where you have split the arguments yourself, not for executing multiple commands.
So you either need to give full paths, or implement the copy yourself in Java.
Change the final line of your program from
Process pp=Runtime.getRuntime().exec(arr);
to:
for (String cmdLine: arr) {
Process pp=Runtime.getRuntime().exec(cmdLine);
and you will execute each line separately, according to RunTime documentation.
You might be better off writing a shell script that does what you need and invoking that from Java.
arr array must store the arguments of command. Not seperated commands. refer to my question.
run shell command from java
If ls -l /home/arps/FBI/hrs1.txt outputs nothing as you said in the comments, then the file you're trying to rename simply does not exist, so the exception is right about this.
PS: IMHO this is not to be done in Java. Use scripting languages for such things. Way easier and way smaller code. For each problem, try to use the right tool, not one tool for all problems.

Categories