Running external executable file from Java program - java

I'm trying to write a Java program which gets a executable file to run under Linux. This executable file receives two parameters and performs a nmap -sP operating with the two given parameters.
I've called this file as file.exe and its content is the one below:
nmap -sP $segment1-$segment1
I already did a chmod +x file.exe and it's in same directory where the .class is present.
The Java code is the following:
import java.lang.Runtime;
import java.lang.Process;
import java.io.IOException;
import java.lang.InterruptedException;
public class runFile {
public static void main (String args[]) throws IOException, InterruptedException {
Runtime r = Runtime.getRuntime();
Process p = r.exec("file.exe "+args[0]+" "+args[1]);
p.waitFor();
}
}
After compiling, Whenever I try to run it (from where the file.exe is) by
java runFile
I'm getting the following exception and errors log:
Exception in thread "main" java.io.IOException: Cannot run program
"file.exe": error=2, No such file or directory at
java.lang.ProcessBuilder.start(ProcessBuilder.java:1041) at
java.lang.Runtime.exec(Runtime.java:617) at
java.lang.Runtime.exec(Runtime.java:450) at
java.lang.Runtime.exec(Runtime.java:347) at
runFile.main(runFile.java:12) Caused by: java.io.IOException: error=2,
No such file or directory at java.lang.UNIXProcess.forkAndExec(Native
Method) at java.lang.UNIXProcess.(UNIXProcess.java:135) at
java.lang.ProcessImpl.start(ProcessImpl.java:130) at
java.lang.ProcessBuilder.start(ProcessBuilder.java:1022) ... 4 more
What am I missing?

The error is telling you that the executable can not be found in the current directory or the OS's search path.
Try including the Pathans part of the command
Process p = r.exec("/path/to/file.exe "+args[0]+" "+args[1]);
You should also consider separating each command/argument as a separate parameter
Process p = r.exec(new String[]{"/path/to/file.exe ", args[0], args[1]});
This will help with parameters that contain spaces.
You should also consider using ProcessBuilder, this will allow you to change the directory context that the command should be executed

Your java program looks for file.exe in the directory where you started your java program. It does not look inside the directory with your class files.

Related

ProcessBuilder("command","-v","date").start() fails with IOException: No such file or directory

I am trying to find out whether a command exists (eg. date) using the command shell builtin, on Ubuntu. However the following (scroll further below for java snippet)
//main.kt
fun main(){
val proc=ProcessBuilder("command","-v","date").start() //line 37
}
fails to run with stack trace
Exception in thread "main" java.io.IOException: Cannot run program "command": error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at MainKt.main(main.kt:37)
at MainKt.main(main.kt)
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 3 more
command is definitely available on my bash -
user#pc:~$ type command
command is a shell builtin
Why does the error occur?
Note that most other similar queries (there are plenty on SO) got solved via syntactic corrections or bad file paths, and don't apply here.
Env:
JDK 17 on Ubuntu 20.04.5 LTS
Java code:
import java.io.IOException;
//rough.java
public class rough {
public static void main(String[] args) throws IOException {
new ProcessBuilder("command","-v","date").start();
}
}
Your first sentence already has the solution:
[…] using the command shell builtin […]
ProcessBuilder execs processes directly and does not invoke a shell. And since a shell-builtin is a functionality provided by the shell and not a binary, it cannot be invoked (directly) with ProcessBuilder.
If you want to run a shell, you need to do so explicitly:
new ProcessBuilder("sh", "-c", "command -v date").start();

Getting No such File or Directory Exception on Ubuntu when trying compile a java project from java.lang.Process

Recently, I have switched to Ubuntu v20.04 from Windows 10 Pro v2004 because of performance purposes. When, I was on Windows I can freely compile a java project from another java program by writing:
String pathToCompiler = "\"C:/Program Files/Java/jdk-14/bin/javac\"";
Process compileProcess = Runtime.getRuntime().exec(pathToCompiler+" -d bin #.sources", null, new File("ProjectPath"))
Where the sources file is a file containing the list of classes of the project
The code above works successfully on Windows 10.
But On Linux(Ubuntu):
if I substitute the value of variable pathToCompiler as
pathToCompiler = "\"/usr/lib/jvm/java-11-openjdk-amd64/bin/javac\""
the below exception is raised up and the program executing the command exits:
"/usr/lib/jvm/java-11-openjdk-amd64/bin/javac" -d bin #.sources
java.io.IOException: Cannot run program ""/usr/lib/jvm/java-11-openjdk-amd64/bin/javac"" (in directory "/home/arham/Documents/Omega Projects/Project0"): error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071)
at java.base/java.lang.Runtime.exec(Runtime.java:592)
at java.base/java.lang.Runtime.exec(Runtime.java:416)
at ide.utils.systems.BuildView.lambda$3(BuildView.java:267)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:340)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:271)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1107)
The problem is that the file actually exists but it says No Such File or Directory
Actually, The program which is compiling the project is a Java IDE that I am creatiing.
Someone please tell if he/she knows how to fix this bug
The Runtime.exec method has several problems that make it difficult to use, and this is one of them. Use the newer ProcessBuilder class instead.
String pathToCompiler = "C:/Program Files/Java/jdk-14/bin/javac";
Process compileProcess = new ProcessBuilder(pathToCompiler, "-d", "bin", "#.sources")
.directory(new File("ProjectPath"))
.start();
The differences are:
Remove the extra quotes from around the path to the executable. If quoting is needed, the system takes care of it.
Pass the each command line arguments as a separate string. This way you don't have to worry about quoting.
Update the path to the following:
String pathToCompiler = "/usr/lib/jvm/java-11-openjdk-amd64/bin/javac/";

Java: No such file or directory when redirecting command line program output to /dev/null

I'm currently working on invoking bash program using java. The bash program output too much message and I want to redirect them to /dev/null. But I encountered a weird error No such file or directory.
Here is my demo.
public static void main(String[] args) {
try {
// Another version I've tried:
// Process p = Runtime.getRuntime().exec("echo a > /dev/null");
ProcessBuilder b = new ProcessBuilder("echo a");
// b.redirectOutput(new File("/dev/null")).redirectErrorStream(true);
b.redirectOutput(ProcessBuilder.Redirect.to(new File("/dev/null")))
.redirectErrorStream(true);
Process p = b.start();
p.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
And the error message as follows:
java.io.IOException: Cannot run program "echo a": error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071)
at test.main(test.java:12)
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:340)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:271)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1107)
... 2 more
I'm using a MacBook with Catalina, and I tried java 1.8.0_231 and 1.8.0_241 from oracle. (I couldn't use higher java version because one of the dependency of my project requires java 8).
To ignore the output from the process, it's easier and more portable to use ProcessBuilder.Redirect.DISCARD than explicitly redirecting to a special file/device such as /dev/null.
b.redirectOutput(ProcessBuilder.Redirect.DISCARD)
.redirectErrorStream(true);
Forget about using Runtime.exec - that method is badly designed and hard to use safely. If you want to do input redirection with the "> /dev/null" style, you need to remember that > is a construct created by the command interpreter shell, not the operating system, and if you want to use it you must run a shell.
Runtime.getRuntime().exec(new String[] {"sh", "-c", "echo a > /dev/null"});

Running yarn job from java program using ProcessBuilder gives file does not exist error

I am trying to run a yarn job from a java wrapper program. The mapreduce jar takes two inputs:
A header file: I dont know the name of the file but the location and file extension and there's only one file at that location
A Input files directory
Apart from these I have an Output directory.
the processbuilder code looks like:
HEADER_PATH = INPUT_DIRECTORY+"/HEADER/*.tsv";
INPUT_FILES = INPUT_DIRECTORY+"/DATA/";
OUTPUT_DIRECTORY = OUTPUT_DIRECTORY+"/";
ProcessBuilder mapRProcessBuilder = new ProcessBuilder("yarn","jar",JAR_LOCATION,"-Dmapred.job.queue.name=name","-Dmapred.reduce.tasks=500",HEADER_PATH,INPUT_DIRECTORY,OUTPUT_DIRECTORY);
System.out.println(mapRProcessBuilder.command().toString());
Process mapRProcess = mapRProcessBuilder.start();
On run, I get the following error:
Exception in thread "main" java.io.FileNotFoundException: Requested
file /input/path/dir1/HEADER/*.tsv does not exist.
But when I run the same command as :
yarn jar jarfile.jar -Dmapred.job.queue.name=name -Dmapred.reduce.tasks=500 /input/path/dir1/HEADER/*.tsv /input/Dir /output/Dir/
It works all fine.
what can be the issue when running the command from java is causing this issue?
The * is being treated as part of the literal string in this case rather than a wildcard. Therefore globbing isn't expanding to your desired path name.
If there is only one file in the directory, why don't you find what its path is and pass that as the argument instead
eg.
File dir = new File(INPUT_DIRECTORY+"/HEADER);
if (dir.list().length > 0)
String HEADER_PATH = dir.list()[0].getAbsolutePath();

ProcessBuilder can't find perl

I'm trying to execute a perl script from java with the following code:
ProcessBuilder script =
new ProcessBuilder("/opt/alert-ssdb.pl");
Process tmp = script.start();
But when I execute it it returns
java.io.IOException: Cannot run program "/opt/alert-ssdb.pl": java.io.IOException: error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:488)
at scripttest.main(scripttest.java:11)
Caused by: java.io.IOException: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.<init>(UNIXProcess.java:164)
at java.lang.ProcessImpl.start(ProcessImpl.java:81)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:470)
... 1 more
about the file
ls -l alert-ssdb.pl
-rwxr-xr-x. 1 root root alert-ssdb.pl
I tried running /usr/bin/perl/ with the script as an argument and it also failed with the same exception.
/bin/ls and other simple commands run without a problem though.
Also the first line of the script is #!/usr/bin/perl
and when run on command line it works
what am I missing?
//Update:
The big picture is that I'm trying to call the script via a storm bolt and it fails at that point.
I managed to make it work by defining a python script as a bolt
using
super(python,myscript.py)
(myscript imports the storm library) and from myscript I call the perl script.
I haven't tried yet but I suppose that If I modify the perl script to be a storm bolt it will run nicely.
Try changing
new ProcessBuilder("/opt/alert-ssdb.pl");
to:
new ProcessBuilder("/usr/bin/perl", "/opt/alert-ssdb.pl");
I've had past experiences where not all my environment variables from the shell exist when using ProcessBuilder.
Edited to reflect #dcsohl's comment.

Categories

Resources