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.
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 have written some code for executing .bat file. which contains some
commands like setting java classpath,etc..And finally there is one command
which runs a Java class file.The HelloWorld class converts some xml file and generating a new xml file in some folder. When I double click .bat file, it executes fine,
but when I try to run I am not getting any output as I was getting through
double click the .bat file. How to make a batch execute and probably it would be nice
if I could see the results through Java console.
Following is MyJava code to execute the .bat file
public void run2() {
try {
String []commands = {"cmd.exe","/C","C:/MyWork/Java/classes/run.bat"} ;
Process p = Runtime.getRuntime().exec(commands);
BufferedReader in = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
And below the some commands which has been set to .bat file
set CLASSPATH=%CLASSPATH%;C:/MyWork/Java
set CLASSPATH=%CLASSPATH%;C:/MyWork/Java/classes
java -cp test.jar;test2.jar test.HelloWorld
Tried with "/C" commad as well. It does not execute. Actually it does not give effect of double click the .bat file. Is there any other way that I can try with?
I can see the contents inside the .bat file through Eclipse console. But it does not give the desired output. Desired output means when I double click .bat file, it executes well. But through java call, I can see the contents only .
When using cmd.exe use /C-Parameter to pass command:
String []commands = {"cmd.exe","/C","C:/MyWork/Java/classes/run.bat"} ;
according to this, the Windows CMD needs the /c argument, to execute commands like this. try this:
String []commands = {"cmd.exe","/c","C:/MyWork/Java/classes/run.bat"} ;
Windows uses \ backslash for Windows and MS-DOS path delimiter. Forward slash / is accepted by Java in the java.io package and translated to be a path delimiter, but will not be directly acceptable to Windows or accepted by the cmd.exe shell.
You may also need to specify either the working directory for the batch file to be executed in, or possibly a full path to the cmd.exe command interpreter.
See: Runtime.exec (String[] cmdarray, String[] envp, File dir)
String[] commands = {"C:\\Windows\\System32\\cmd.exe", "/c",
"C:\\MyWork\\Java\\classes\\run.bat"};
File workDir = new File( "C:/MyWork");
Process process = Runtime.getRuntime().exec( commands, null, workDir);
To verify if the batch file is run at all, add a pause command to the batch file. That will keep the window open so you can verify if the batch file is launched at all, and debug this stage-by-stage.
You do not read the error output of your batch file, therefore, you'll never see any error messages printed from there or from CMD.EXE itself. In addition, the sub-program may stall and just wait for you to read the error stream.
Please see related discussions here: How to make a java program to print both out.println() and err.println() statements?
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 currently have a java program that uses xcopy with Runtime.exec to copy files. But the problem now is that when the file name has chinese characters this does not work.
It gives a file not found error.
However if i copy the file path from explorer and do xcopy from the command line copy works.
I am executing it from a Windows 7 machine. Any solutions will be much appreciated.
Thanks
This is related to the bug http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4947220. Instead of passing the parameters as arguments, passed them via environment variables which worked perfectly.
Why are you using xcopy? Use java.
Try to do it with java.nio.file.Files
Path a = ...
Path b = ...
Files.copy(a,b);
See here for doc:
http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#copy(java.nio.file.Path,%20java.nio.file.Path,%20java.nio.file.CopyOption...)
The exec in Java converts the strings to the system code page.
Shameful, for the XXI century, but that's how it is.
But Java is not the only bottleneck here. The console is also problematic, and xcopy might have it's own share.
There is a lot of voodoo that you can try, for instance starting cmd.exe as Unicode (/U), and/or setting the code page to utf-8 (chcp 65001), or create a batch file with the command and call that batch (so no high-ascii in the exec function).
But I would not relay on that.
Since everything is Windows only anyway, I would probably try using jni to implement a "proper" exec, or see if FileCopy is faster than the Java copy.
If you need to copy large files, or files and all the system permissions associated with a file, using java internal File.copy() will be too expensive, so you can offload all the load to your system.
Try the following trick - first, user string array as an argument to exec(); second, execute your 'xcopy' in a pipe after 'cmd' command with /C argument. Look at the sample code near line where I make isWindows() call.
The trick is that your xcopy command will be executed inside CMD shell, and /C will terminate it after successful execution. More aboutCMD.exe.
public int sysCopyFile(Resource fromResource, Resource toResource) throws ServiceException {
int returnCode = -1;
try {
String[] copyCommand = null;
if ( IOUtils.isWindows() ) {
copyCommand = new String[] {"cmd", "/C", "copy", "/Y", fromResource.getFile().getAbsolutePath(), toResource.getFile().getAbsolutePath()};
} else if ( IOUtils.isUnix() || IOUtils.isMac() ) {
copyCommand = new String[] {"/bin/cp", "-pr", fromResource.getFile().getAbsolutePath(),toResource.getFile().getAbsolutePath()};
}
final Process p = Runtime.getRuntime().exec(copyCommand);
new StreamLogger(p.getErrorStream(), log, StreamLogger.WARN);
new StreamLogger(p.getInputStream(), log, StreamLogger.DEBUG);
returnCode = p.waitFor();
if (returnCode != 0) throw new ServiceException("Unable to to copy. Command: {" + copyCommand[0] + "} has returned non-zero returnCode: " + returnCode);
} catch (IOException e) {
throw new ServiceException(e);
} catch (InterruptedException e) {
throw new ServiceException(e);
}
return returnCode;
}
How to execute a java program with the help of Runtime.getRuntime().exec().
For example we shall have the java file path as c:/java/abc.java. Please help me with the code.
Assuming that abc.java contains a main method that you want to execute:
Runtime.getRuntime().exec("javac c:\java\abc.java -d c:\java\")
Runtime.getRuntime().exec("java c:\java\abc")
Do not forget that:
you may need to read stdout/stderr of a java program
you may have to set/update environment variable and PATH before executing your java command
CreateProcess: c:\j2sdk1.4.0\bin\helloworld error=2
means Win32's CreateProcess returns a 2 as error code when it cannot find the command you specify; more specifically, when the command does not refer to an executable file on its lookup path.
Look at this SO question for a more complete "Runtime.getRuntime().exec()" code, and also to this snippet.
This code creates a shell (as in Runtime.getRuntime().exec("cmd /K")), in which you write on sdtin whatever command you want to execute.
The interest of this approach is to reuse the shell process to benefit from a previous command: it you execute a 'cd', then execute a 'dir', the latter command would display the content of the directory referenced by the cd command.
The same would be true for PATH settings, just before using javac or java.
You should use ProcessBuilder instead of Runtime. Basic usage is like:
Process process = new ProcessBuilder(command).start();
You will find more code under the link above. Also see this question.
You mean you want a Java program to run another Java program. This SO thread might be helpful, in that case.
String path1 = "f://" + File.separator+username+File.separator+progName;
Runtime runtime = Runtime.getRuntime();
String command = "javac -classpath " + path + " " + path1;
System.out.println(command);
Process process = runtime.exec(command);
InputStream error = process.getErrorStream();
Please see the excellent resource which used to be called javaalmanac.
http://www.exampledepot.com/egs/java.lang/Exec.html
try {
// Execute a command with an argument that contains a space
String[] commands = new String[]{"grep", "hello world", "/tmp/f.txt"};
commands = new String[]{"grep", "hello world", "c:\\Documents and Settings\\f.txt"};
Process child = Runtime.getRuntime().exec(commands);
} catch (IOException e) {
}