I'm working with the java ProcessBuilder class to start an instance of nmap on my windows workstation.
The following code produces an exception:
java.io.IOException: Cannot run program "C:\Program Files (x86)\Nmap\nmap.exe -T4 -A -v --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -oX - 192.168.1.1 ": CreateProcess error=2, The system cannot find the file specified
The value of command is:
C:\Program Files (x86)\Nmap\nmap.exe -T4 -A -v --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -oX - 192.168.1.1
Running the command is generated right in a command window executes properly.
Any ideas?
String command = this.getCommand().toString();
ExecutionResults results = new ExecutionResults();
ProcessBuilder procBuilder = new ProcessBuilder(new String[]{command.toString()});
try {
Process e = procBuilder.start();
results.setErrors(this.convertStream(e.getErrorStream()));
results.setOutput(this.convertStream(e.getInputStream()));
You're passing the whole command (including parameters) as a single parameter of the ProcessBuilder constructor. It takes a String[], where the first item should be the path to the executable, and the other items should be the parameters. Try
command.split(" ")
instead of
new String[]{command.toString()}
Edit: I see that you have spaces in your path, that will break it :( you could try splitting the executable path and the arguments into two strings. And the constructor argument will be a String[] containing the path itself as the first item and then an array of the parameters split by space.
OR: if you don't mind not using the ProcessBuilder.. this is much simpler:
Process e = Runtime.getRuntime().exec(command);
It is simple from the exception itself,
java.io.IOException: Cannot run program "C:\Program Files (x86)\Nmap\nmap.exe -T4 -A -v --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -oX - 192.168.1.1 ": CreateProcess error=2, The system
Process builder taking the whole line thinking it is as an executable and trying to run that. Just use the below example,
ProcessBuilder procBuilder = new ProcessBuilder(new String[]{"C:\Program Files (x86)\Nmap\nmap.exe"});
procBuilder.start();
This will work fine. So this is not an issue what you think that java is unable to find the executable. It is taking whole line as an executable. Better you do like below,
ProcessBuilder procBuilder = new ProcessBuilder(new String[]{"C:\Program Files (x86)\Nmap\nmap.exe", "-T4", "-A"}); //add all params
procBuilder.start();
Try this, it should work fine
As the other answers have indicated, your immediate problem is that you're passing an entire command line as if it's the name of a program to run. CreateProcess is looking for a program named "C:\Program Files (x86)\Nmap\nmap.exe -T4 -A etc" and failing to find it.
If you have a string containing a command to run (a program name with arguments, redirection, and so on), then the simplest way to run it is to launch it via the command line processor. Here's a simple example of doing that:
public static void main(String[] args) throws IOException, InterruptedException {
String command = "dir /w";
ProcessBuilder procBuilder = new ProcessBuilder(new String[]{"cmd", "/c", command});
procBuilder.redirectInput(Redirect.INHERIT);
procBuilder.redirectOutput(Redirect.INHERIT);
procBuilder.redirectError(Redirect.INHERIT);
Process p = procBuilder.start();
int ecode = p.waitFor();
System.err.println("Exit code " + ecode);
}
It might be because of a couple of reasons from my experience
Firewall would be removed certain files necessary for the installer. So would suggest to uninstall and reinstall
Can also be because of spaces in the folder path, would suggest to install in new folder which does not have spaces in the path.
Related
I am currently trying to write a small program in java which should take over the job of an old batch script I've been using.
This batch script executes a program called sum.exe (Supermicro Update Manager).
However, no matter which way I try, the program either does not respond, or straight up tells me it can't find the file in the directory where the file is.
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
ProcessBuilder builder = new ProcessBuilder("C:\\Users\\[Username]\\SUM\\sum.exe");
if (isWindows) {
builder.command("sum.exe", "-i 192.168.4.10 -u ADMIN -p ADMIN -c CheckOOBSupport");
} else {
builder.command("sh", "-c", "ls");
}
builder.redirectErrorStream(true);
Process process = builder.start();
StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println);
StreamGobbler streamGobblerErrors = new StreamGobbler(process.getErrorStream(), System.out::println);
Executors.newSingleThreadExecutor().submit(streamGobbler);
Executors.newSingleThreadExecutor().submit(streamGobblerErrors);
int exitCode = process.waitFor();
assert exitCode == 0;
This is the code I currently have. The command I'm trying to call here will 100% give an error, so I made sure to redirect those as well.
As far as I understood, there are 3 different ways to set a Filepath for the Processbuilder.
Either you:
Set the path in the constructor
Set the path between your executable and arguments in the .command() method
Or you set the directory of the builder by creating a new file (and using System.Property)
I have a complete copy of the SUM-Folder under: C:\Users\[Username]\SUM, and I have tried all 3 options listed above with this, but always got the error message that the system could not find the file specified
Additionally, I'm still not sure if the command would even work this way. I have only ever used sum.exe via batch-Script or cmd.exe itself, so wouldn't the command need to be
builder.command("cmd.exe", "sum.exe -i 192.168.4.10 -u ADMIN -p ADMIN -c CheckOOBSupport)
instead?
Can anyone tell me what I'm doing wrong?
Thanks!
The ProcessBuilder command line is passed in the constructor or the command() method so in your example you've overridden the value used.
Choose the way you need:
ProcessBuilder builder = new ProcessBuilder("C:\\Users\\[Username]\\SUM\\sum.exe",
"-i", "192.168.4.10",
"-u", "ADMIN","-p", "ADMIN",
"-c", "CheckOOBSupport");
or
ProcessBuilder builder = new ProcessBuilder();
builder.command("sum.exe",
"-i", "192.168.4.10",
"-u", "ADMIN","-p", "ADMIN",
"-c", "CheckOOBSupport");
Note also that the arguments for the command need to supplied as separate string values rather than all concatenated together as one value, and you need absolute path to "sum.exe" if that is not found in the current directory or under a directory of environment variable "Path".
I am trying to run a .jar file via another program. For example, I have a HelloWorld.jar file which opens a dialog saying "Hello World". And I have a Test.jar program. When I do something in the Test.jar (i.e. click some button), it should run the HelloWorld.jar.
The way I am currently doing so is running a terminal command java -jar HelloWorld.jar using ProcessBuilder. However, I get this error:
Debug: "C:\Users\Asus\.fairplay\data\apps\Amnesia\.tmp524\.bin" exists: true
java.io.IOException: Cannot run program "java -jar Amnesia.jar" (in directory "C:\Users\Asus\.fairplay\data\apps\Amnesia\.tmp524\.bin"): CreateProcess error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at me.darksidecode.fairplay.client.util.Utils.execute(Utils.java:74)
at me.darksidecode.fairplay.client.app.AppLauncher.launch0(AppLauncher.java:61)
at me.darksidecode.fairplay.client.app.AppLauncher.launch(AppLauncher.java:37)
at me.darksidecode.fairplay.client.app.AppLoader.downloadAndRun(AppLoader.java:28)
at me.darksidecode.fairplay.client.gui.frame.GuiLauncher.onPacketReceiving(GuiLauncher.java:165)
at me.darksidecode.fairplay.client.core.FairPlayClient.lambda$processPacket$1(FairPlayClient.java:120)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: CreateProcess error=2, No such file or directory
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(ProcessImpl.java:386)
at java.lang.ProcessImpl.start(ProcessImpl.java:137)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 7 more
I am 100% sure that both the file and the directory exist, and I even checked that. As you can see in the error over here, there is also a debug message proving that.
My code for command execution:
public static Process execute(final String path, final String cmd, final boolean removeJavaOptions) {
File f = Files.getFile(path);
System.out.println("Debug: \"" + f.getAbsolutePath() + "\" exists: " + f.exists());
try {
final ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(Files.getFile(path));
pb.redirectErrorStream(true);
if (removeJavaOptions)
pb.environment().remove("_JAVA_OPTIONS");
return pb.start();
} catch (final Exception ex) {
ex.printStackTrace();
return null;
}
}
The usage of this method itself:
Utils.execute(bin.getAbsolutePath().replace(bin.getName(), ""), "java -jar " + bin.getName(), false);
I have not found any useful answers to this question on StackOverflow or anywhere else yet. Hopefully there is a solution to solve this.
The ProcessBuilder constructor accepts either a List<String>, or a varargs (several strings), e.g.
new ProcessBuilder( "command", "arg1", "arg2", "arg3" );
Instead of passing it the commands and the arguments separately, you have tried to pass it the command together with the arguments in the same string.
The builder interprets the first argument as the name of the command. Thus, it believes that you are trying to run a file called java -jar Amnesia.jar. It thinks you simply have an executable file with spaces in its name. But of course, the operating system can't find such an executable file.
What you should do is run the command with the arguments separated from the command, that is:
new ProcessBuilder( "java", "-jar", "Amnesia.jar" );
So you'll need to reconstruct your execute method, such that either the cmd parameter is a List<String>, an array (String[]), or it is the last parameter and is a varargs parameter.
I'm trying to use the Java function Runetime.exec(String) to run a program in the startup folder of a windows 7 computer like so:
Runtime.getRuntime().exec(runner.getPath() + "\\run.bat");
And when I run this I get an error saying the command cannot be run:
Exception in thread "main" java.io.IOException: Cannot run program ""C:\Users\ly
ndsey\AppData\Roaming\Microsoft\Windows\Start": CreateProcess error=2, The syste
m cannot find the file specified
As you can see, the file name is cut off at the "\Windows\Start" when it should continue to "\Windows\Startup\run.bat".. Is there an alternative I can use?
Considering runner as a File instance, this should work.
Desktop.getDesktop().open(new File(runner, "run.bat"));
It uses Desktop class instead of Runtime, so you don't have to convert your File (runner) to its String representation (which is error prone). Runner is now used 'as is' as the parent directory of the "run.bat" you want to execute.
Other advantage of Desktop class : you can now open any file you want.
As an alternative you can use ProcessBuilder. I feel ProcessBuilder is more safe than Runtime.getRuntime().exec http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
String[] command = {"CMD", "/C", "dir"};
ProcessBuilder pb = new ProcessBuilder( command );
//set up your work directory if needed
pb.directory(new File("c:\\path"));
Process process = pb.start();
as i can see from the error you give, and i hope it's a copy past, you string runner.getPath() for some reason start and end with "\"" which make the whole path invalid. check that and remove it if needed
if you have the file already and you just need it's path you can use
runner.getAbsolutePath()
also, if runner is a file, getPath will give you the file path including the path, so your code will surely won't work. instead use:
String path = runner.getPath();
path = path.substring(0, path.lastIndexOf("\\")) + "\\run.bat";
Runtime.getRuntime().exec(path);
You should avoid the exec(String) method, which attempts to parse the entire string into command + arguments. The safe option is exec(String[]), which presupposes the first array element is the command and the rest are arguments.
So, writing
Runtime.getRuntime.exec(new String[] { yourCommandString })
is a surefire way of getting the right message across.
i'm trying to execute a SOX command from java, but unfortunately its returning an error everytime. Every other SOX commands are working perfectly though!!
Here is the code :
class Simple {
public static void main(String args[]) throws IOException, Exception {
Process p;
BufferedReader br;
String co = "sox speech_16.wav -p pad 0 2.5 | sox - -m speech_16.wav speech_output.wav";
p = Runtime.getRuntime().exec(co);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
int returnCode = p.waitFor();
System.out.println("reurn code : "+returnCode);
}
}
When I'm executing the same sox command in terminal, its working fine. I really can't understand what the problem is!! Is it because of the '|' symbol??
The issue is that Runtime.exec() does not understand shell concepts such as "|". Instead try:
Runtime.getRuntime().exec("/bin/sh", "-c", co);
The problem is that exec runs a binary directly without invoking the shell. The "|" character is only recognized by the shell, not by sox. The "-c" tells the shell to run a single command, and passes the entire command as the single argument.
This is likely to be related to the environment in which the commands get executed, it could be any of the following:
The sox executable cannot be found (put the full path in the command)
The user does not have permission to run the sox command (check execute bit in file permissions)
Some environment variable needed by sox is not initialised when you run the command from Java (check sox documentation)
If speech_16.wav is an input file to sox then the file cannot be found (add full path of .wav file to command)
If sox needs to create an output file then it does not have permission to do so, either due to directory permissions, of because there is an existing file with that name which cannot be overwritten, or due to lack of space on the file-system.
I've created a standalone java application in which I'm trying to change the directory using the "cd" command in Ubuntu 10.04 terminal. I've used the following code.
String[] command = new String[]{"cd",path};
Process child = Runtime.getRuntime().exec(command, null);
But the above code gives the following error
Exception in thread "main" java.io.IOException: Cannot run program "cd": java.io.IOException: error=2, No such file or directory
Can anyone please tell me how to implement it?
There is no executable called cd, because it can't be implemented in a separate process.
The problem is that each process has its own current working directory and implementing cd as a separate process would only ever change that processes current working directory.
In a Java program you can't change your current working directory and you shouldn't need to. Simply use absolute file paths.
The one case where the current working directory matters is executing an external process (using ProcessBuilder or Runtime.exec()). In those cases you can specify the working directory to use for the newly started process explicitly (ProcessBuilder.directory() and the three-argument Runtime.exec() respectively).
Note: the current working directory can be read from the system property user.dir. You might feel tempted to set that system property. Note that doing so will lead to very bad inconsistencies, because it's not meant to be writable.
See the link below (this explains how to do it):
http://alvinalexander.com/java/edu/pj/pj010016
i.e. :
String[] cmd = { "/bin/sh", "-c", "cd /var; ls -l" };
Process p = Runtime.getRuntime().exec(cmd);
Have you explored this exec command for a java Runtime, Create a file object with the path you want to "cd" to and then input it as a third parameter for the exec method.
public Process exec(String command,
String[] envp,
File dir)
throws IOException
Executes the specified string command in a separate process with the specified environment and working directory.
This is a convenience method. An invocation of the form exec(command, envp, dir) behaves in exactly the same way as the invocation exec(cmdarray, envp, dir), where cmdarray is an array of all the tokens in command.
More precisely, the command string is broken into tokens using a StringTokenizer created by the call new StringTokenizer(command) with no further modification of the character categories. The tokens produced by the tokenizer are then placed in the new string array cmdarray, in the same order.
Parameters:
command - a specified system command.
envp - array of strings, each element of which has environment variable settings in the format name=value, or null if the subprocess should inherit the environment of the current process.
dir - the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process.
Returns:
A new Process object for managing the subprocess
Throws:
SecurityException - If a security manager exists and its checkExec method doesn't allow creation of the subprocess
IOException - If an I/O error occurs
NullPointerException - If command is null, or one of the elements of envp is null
IllegalArgumentException - If command is empty
This command works just fine
Runtime.getRuntime().exec(sh -c 'cd /path/to/dir && ProgToExecute)
Using one of the process builder's method we could pass the directory where we expect the cmd to be executed. Please see the below example. Also , you can mention the timeout for the process, using wait for method.
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", cmd).directory(new File(path));
Process p = builder.start();
p.waitFor(timeoutSec, TimeUnit.SECONDS);
In the above code, you can pass the file object of the path[where we expect the cmd to be executed] to the directory method of ProcessBuilder
My preferred solution for this is to pass in the directory that the Runtime process will run in. I would create a little method like follows: -
public static String cmd(File dir, String command) {
System.out.println("> " + command); // better to use e.g. Slf4j
System.out.println();
try {
Process p = Runtime.getRuntime().exec(command, null, dir);
String result = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
String error = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
if (error != null && !error.isEmpty()) { // throw exception if error stream
throw new RuntimeException(error);
}
System.out.println(result); // better to use e.g. Slf4j
return result; // return result for optional additional processing
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Note that this uses the Apache Commons IO library i.e. add to pom.xml
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
</dependency>
To use the cmd method e.g.
public static void main(String[] args) throws Exception {
File dir = new File("/Users/bob/code/test-repo");
cmd(dir, "git status");
cmd(dir, "git pull");
}
This will output something like this: -
> git status
On branch main
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
> git pull
Already up to date.
Try Use:
Runtime.getRuntime.exec("cmd /c cd path");
This worked
Runtime r = Runtime.getRuntime();
r.exec("cmd /c pdftk C:\\tmp\\trashhtml_to_pdf\\b.pdf C:\\tmp\\trashhtml_to_pdf\\a.pdf cat output C:\\tmp\\trashhtml_to_pdf\\d.pdf");
The below did not work
While using array command did NOT WORK
String[] cmd = {"cmd /c pdftk C:\\tmp\\trashhtml_to_pdf\\b.pdf C:\\tmp\\trashhtml_to_pdf\\a.pdf cat output C:\\tmp\\trashhtml_to_pdf\\d.pdf"}; r.exec(cmd);
FYI am using utility to check OS if its windows above will work for other than windows remove cmd and /c
I had solved this by having the Java application execute a sh script which was in the same directory and then in the sh script had done the "cd".
It was required that I do a "cd" to a specific directory so the target application could work properly.