This question already has answers here:
How to execute script from JAR file?
(3 answers)
Closed 7 years ago.
I have class that invokes perl script:
Runtime.getRuntime().exec(perlscript.pl)
The class and the script are placed on the same jar archive. This jar was built by maven. And perl script was placed in root of the jar, but the class not in root path.
When I launch the perl script I get error: "The system cannot find the file specified"
Where should I place the script to properly invoke it?
This works both, in Eclipse and as a Maven-built jar. Following what is said in this SO answer, what I've done is (i) find the original script within the jar, (ii) copy its content into a newly created file within a temporary folder and finally (iii) -- execute that script:
// find the original script within the JAR,
// mine sits in /src/main/resources/Perl/Hello.pl
InputStream in = PerlCaller.class.getClass().getResourceAsStream("/Perl/Hello.pl");
// if the file in the jar's root
// InputStream in = PerlCaller.class.getClass().getResourceAsStream("/Hello.pl");
if (null == in) {
System.err.println("Resource ws not found, exiting...");
System.exit(10);
}
// copy its content into a temporary file, I use strings since it's a script
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
File scriptFile = File.createTempFile("perlscript", ".pl");
BufferedWriter bw = new BufferedWriter(new FileWriter(scriptFile));
String line;
while ((line = reader.readLine()) != null) {
bw.write(line + "\n");
}
bw.close();
// execute the newly created file
String[] command = { "perl", scriptFile.getAbsolutePath() };
final ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
final Process p = pb.start();
BufferedReader outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuilder builder = new StringBuilder();
String outputLine = null;
while ((outputLine = outputReader.readLine()) != null) {
builder.append(outputLine);
builder.append(System.getProperty("line.separator"));
}
String scriptOutput = builder.toString();
System.out.println(scriptOutput);
Hope this helps!
You can access you script as a stream like:
Thread.currentThread().getContextClassLoader().getResourceAsStream("script.pl");
if your script is not in the root of classpath, use slashes to point to it like:
"path/to/script/script.pl"
Related
I have two programms "a" and "b" bot compiled to fatJar files. "b" is added as resource to "a". I now want "a" to execute "b" using a process builder. As far as I understand it I cannot directly give the process builder the "b" jar for it doesn't exist in the regular windows file system.
The suggested solution to this is to access "b" as resource and write its content to a temp file and then hand the temp file to the process builder.
My question is: how do i copy the fatJar "b" into a temp file in a way it stays executionable?
My current approach looks like this:
try {
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
try (InputStreamReader streamReader =
new InputStreamReader(stream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)) {
String line;
while ((line = reader.readLine()) != null) {
Files.write(tempFile, reader.readLine().getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
processBuilder.redirectErrorStream(true);
System.out.println(process.isAlive());
The process.isAlive() call confirms the process is running however the process doesn't function as it should (it should build up a two way communication via the input and output streams but i won't get any answer from the running process).
Does anyone know if there is an better approach to the whole situation or if my way of copying the .jar to the temp file is wrong?
Ok so meanwhile i figured it out. Turns out the Buffered reader caused the problem. The below code works fine now.
Path tempFile = Files.createTempFile("b", ".jar");
InputStream stream = Main.class.getClassLoader().getResourceAsStream("b.jar");
byte[] line = stream.readAllBytes();
Files.write(tempFile, line);
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", tempFile.getFileName().toString());
processBuilder.directory(new File(tempFile.getParent().toString()));
Process process = processBuilder.start();
Java code
try {
String command = "/opt/compress.sh param1 param2 param3";
Process ps = Runtime.getRuntime().exec(command);
ps.waitFor(60 * 5, TimeUnit.SECONDS);
br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
result = sb.toString();
log.info("shell logļ¼\n" + result);
}finally {
br.close();
}
shell Code
#Other business codes
zip -m -jP $3 ${zipOutPath} ${fileIputPath}
The workflow engine calls jar packages to execute Java code, and the zip command in the shell often fails. Manually executing the JAR package on the server is normal.Zip compresses only a CSV file,the file size is 2G.Try to enable shell Debug, only get -> addling XXx. CSV (%)
You are not consuming output streams properly so this may lead to freeze, and waitFor must be after reading STDOUT. Try using ProcessBuilder instead and see what errors it reports, it may help you to the next step:
ProcessBuilder pb = new ProcessBuilder(cmd);
// No STDERR => merge to STDOUT (or redirect elsewhere)
pb.redirectErrorStream(true);
Process p = pb.start();
try(var merged = p.getInputStream()) {
merged.transferTo(System.out);
}
// Check the executable worked:
int rc = p.waitFor();
if (rc != 0)
throw new RuntimeException("failed: "+Arrays.toString(cmd));
I am running some .jar programs from a Java code. To do that, I use ProcessBuilder, as follows:
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jarFile, configFile);
Process p = pb.start();
finished = p.waitFor(600, TimeUnit.SECONDS);
// print the error output
if(finished){
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ( (line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
result = builder.toString();
reader.close();
status = p.exitValue();
}
else{
p.destroyForcibly();
result = "Error: maximum time (600 seconds) exceeded.";
}
The above code is within a foor bucle that selects different jar files (using the jarFile variable) at each iteration. Each one of the jar files writes some output files (note that these output files are different from the standard output / standard error of the program, they are other additional output files).
The problem is that, sometimes, some of the jar programs do not create its corresponding files. If I re-run the code several times, the processes that write their output files are different in each execution (which is very rare).
Could someone give me an indication on how to solve this problem? Thanks in advance.
I'm developing java application which allow to white or paste a source-code and run it without doing compiling procedure manually.what it do is save java code from text-box to a text-file and execute cmd command java java-file after execute javac java-file.file.
it's work fine but this problem came across when java file doesn't have any output .i mean if code create a swing form ..cmd haven't any output.then my java program get stuck actually i can't close it.i have to use external program to close it like taskmanager.
but when source-code has command-line output this problem never occurred .
OutputStream stdin = null;
BufferedReader br = null;
String line = null;
String command = null;
command = jTextField1.getText();
System.out.println(command);
Process p = Runtime.getRuntime().exec(command);
stdin = p.getOutputStream(); //use this to push commands
//processing stdout
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
// br.flush();
byte[] bytes = new byte[4096];
///////////////////////////////////////////
BufferedInputStream in = new BufferedInputStream(p.getInputStream());
while (in.read(bytes) != -1)
{
jTextArea1.append(br.readLine()+"\n");
}
///////////////////////////////////////////
I am trying to run a binary file, which is Genia Sequence Splitter through java code. This Binary file is type x-executable and has no extension. I can run the file in terminal by using ./geniass arg1 arg2
where arg1 is input file arg2 is output file
I want to automate this process. I tried using this code
public class geniaSSTag {
public static void geniaSS(String inputFile){
System.out.println("Input file: "+inputFile);
String[]cmd={"bash","geniass/./geniass","in.txt","out.txt"};
try {
String errOutput="";
Process process = Runtime.getRuntime().exec(cmd);
String s = "";
BufferedReader br = new BufferedReader(new InputStreamReader(process
.getInputStream()));
while ((s = br.readLine()) != null)
{
s += s + "\n";
}
System.out.println(s);
BufferedReader br2 = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while (br2.ready() && (s = br2.readLine()) != null)
{
errOutput += s;
}
System.out.println(errOutput);
} catch (IOException ex) {
Logger.getLogger(geniaSSTag.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
But I get this error when I try to run
geniass/./geniass: geniass/./geniass: cannot execute binary file
How can I solve this. Any help is appreciated.
Thank you
When you run the program, is the executable relative to the program's starting directory in the manner that it lies in "./genias/genias"? Note that the "/./" doesn't do anything except waste space, as it is shorthand for "the subdirectory that links back to the current directory".
Perhaps your "genias" executable isn't in a subdirectory named "genias", or the launching program is being launched from a different directory and can't find "genias/genias" relative to it's directory.
As suggested elsewhere, you can fix this by using an absolute path in the launching command. However, sometimes this just isn't flexible enough if you want multiple copies installed.
I would try first to run the command pwd from Java to see where you actually are. Then you can change the path to your executable accordingly. I guess using the path /home/xxx/yyy/geniass would always work.
Also there is a different version of Runtime.exec() which takes a working directory as an argument.
Try:
String[]cmd={"/full/path/to/geniass","in.txt","out.txt"};
Instead