Running bash file from Java is not working - java

try{
//String[] cmd = new String[]{"/bin/sh", "send.sh"};
//Process pr = Runtime.getRuntime().exec(cmd); //nothing happens
//Process p = Runtime.getRuntime().exec("send.sh"); //File not found
//Process p = Runtime.getRuntime().exec("bash send.sh"); //nothing happens
// ProcessBuilder pb = new ProcessBuilder("bash","send.sh");
// Process p = pb.start(); //nothing happens
}
catch(Throwable t)
{
t.printStackTrace();
}
With this code I am trying to start a simple bash file which is located in the directory of the program. The code of the bash file works when I start it with shell or by simply executing it. The code of the bash file works.
I've tried every option but they are all not working. I've commented what happens in each case. I don't understand that it don't find the file because the bash file is located in the same directory.

You don't see an output for two reasons:
You don't wait for a process to finish
You don't redirect it's output to the same console that your Java process runs
And, probably, you need to use a command like /bin/bash -c path/to/your/file.sh. Note that -c flag.
IMHO, the best way to craft and execute external processes in Java is java.lang.ProcessBuilder.
Supposing that you have your sh file somewhere the in resources directory, here is an example main class:
public class App {
public static void main(String[] args) throws Exception {
final ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", App.class.getResource("/46964369.sh").getPath());
processBuilder.redirectInput(Redirect.INHERIT);
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
processBuilder.start().waitFor();
}
}
Note that I redirect process's streams with redirect* methods. Redirect.INHERIT redirects stream to the corresponding stream of the JVM instance. It works both for input and output streams. Finally, I am waiting for a process to finish with waitFor() method. In fact, you can do more, like capturing the output into a string, providing input from a string or running the process asynchronously, but this is a minimal example.
If you store your sh file in another place, you must update path-related logic.
Take a look at the complete example here. It's a Gradle project, and you can use ./gradlew run to execute it:
$ ./gradlew run
:compileJava
:processResources
:classes
:run
Hello, world!
BUILD SUCCESSFUL in 4s
3 actionable tasks: 3 executed

Related

Java shutdown hook not launching my Process

I'm trying to give to my app self update ability.
It download an JAR from my website and save it as myapp.jar.new.
After that, I want to launch a command to delete the current version and rename the new one.
This is my code (see the notes):
public void applyUpdateAndRestart() {
Runtime rt = Runtime.getRuntime();
rt.addShutdownHook(new Thread(() -> {
try {
String updateCmd = "restart.cmd";
try (PrintStream ps = new PrintStream(new FileOutputStream(updateCmd))) {
ps.println("#echo off");
// wait for a while to the main process closes and the "myapp.jar" to be writable
ps.println("ping 127.0.0.1 -n 2 > nul");
ps.println("del /q myapp.jar.old");
ps.println("move myapp.jar myapp.jar.old");
ps.println("move myapp.jar.new myapp.jar");
ps.println("java -jar myapp.jar");
}
ProcessBuilder p = new ProcessBuilder();
p.command("cmd", "/c", updateCmd);
System.out.println("Before apply update");
p.start(); // this does not launch
System.out.println("After apply update"); // this prints!
} catch (Throwable e) {
e.printStackTrace(); // this does not occurs!
}
}));
System.exit(0);
}
Why my update.cmd does not start?
Solved with this approach:
After download my jar to new-myapp.jar, I launch it with an special argument like this: java -jar new-myapp.jar --do-update (running the new jar will unlock the current to be overwritten)
My main mehtod intercept the argument --do-update who applies the new jar to current (copy new-myapp.jar myapp.jar).
After the new jar was copied, It launches itself again using the overwritten jar (java -jar myapp.jar)
I think that Klitos comment can solve my problem too, but I solved implementing my previous approach.
On the approach of the question the problem was that the cmd /c haven't a console window allocated. Changing the command to cmd /c start solve the problem too because the start command allocate a new console window.
My idea - since you just call start() for process and finish the shutdown hook - the process dies with your main java process. Try to call Process.waitFor() to have you shutdown hook thread waiting until external process finished.
I think that you can't do it like you want. You want to remove the jar of the application but the app is running and therefore could not be removed.
My suggestion is use a launcher.cmd that look for a new.jar if it finds it remove old.jar and rename new.jar and THEN launch java -jar old.jar.

Trying to show the execution of bat file in eclipse console [duplicate]

In my Java application, I want to run a batch file that calls "scons -Q implicit-deps-changed build\file_load_type export\file_load_type"
It seems that I can't even get my batch file to execute. I'm out of ideas.
This is what I have in Java:
Runtime.
getRuntime().
exec("build.bat", null, new File("."));
Previously, I had a Python Sconscript file that I wanted to run but since that didn't work I decided I would call the script via a batch file but that method has not been successful as of yet.
Batch files are not an executable. They need an application to run them (i.e. cmd).
On UNIX, the script file has shebang (#!) at the start of a file to specify the program that executes it. Double-clicking in Windows is performed by Windows Explorer. CreateProcess does not know anything about that.
Runtime.
getRuntime().
exec("cmd /c start \"\" build.bat");
Note: With the start \"\" command, a separate command window will be opened with a blank title and any output from the batch file will be displayed there. It should also work with just `cmd /c build.bat", in which case the output can be read from the sub-process in Java if desired.
Sometimes the thread execution process time is higher than JVM thread waiting process time, it use to happen when the process you're invoking takes some time to be processed, use the waitFor() command as follows:
try{
Process p = Runtime.getRuntime().exec("file location here, don't forget using / instead of \\ to make it interoperable");
p.waitFor();
}catch( IOException ex ){
//Validate the case the file can't be accesed (not enought permissions)
}catch( InterruptedException ex ){
//Validate the case the process is being stopped by some external situation
}
This way the JVM will stop until the process you're invoking is done before it continue with the thread execution stack.
Runtime runtime = Runtime.getRuntime();
try {
Process p1 = runtime.exec("cmd /c start D:\\temp\\a.bat");
InputStream is = p1.getInputStream();
int i = 0;
while( (i = is.read() ) != -1) {
System.out.print((char)i);
}
} catch(IOException ioException) {
System.out.println(ioException.getMessage() );
}
ProcessBuilder is the Java 5/6 way to run external processes.
To run batch files using java if that's you're talking about...
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);`
This should do it.
The executable used to run batch scripts is cmd.exe which uses the /c flag to specify the name of the batch file to run:
Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "build.bat"});
Theoretically you should also be able to run Scons in this manner, though I haven't tested this:
Runtime.getRuntime().exec(new String[]{"scons", "-Q", "implicit-deps-changed", "build\file_load_type", "export\file_load_type"});
EDIT: Amara, you say that this isn't working. The error you listed is the error you'd get when running Java from a Cygwin terminal on a Windows box; is this what you're doing? The problem with that is that Windows and Cygwin have different paths, so the Windows version of Java won't find the scons executable on your Cygwin path. I can explain further if this turns out to be your problem.
Process p = Runtime.getRuntime().exec(
new String[]{"cmd", "/C", "orgreg.bat"},
null,
new File("D://TEST//home//libs//"));
tested with jdk1.5 and jdk1.6
This was working fine for me, hope it helps others too.
to get this i have struggled more days. :(
I had the same issue. However sometimes CMD failed to run my files.
That's why i create a temp.bat on my desktop, next this temp.bat is going to run my file, and next the temp file is going to be deleted.
I know this is a bigger code, however worked for me in 100% when even Runtime.getRuntime().exec() failed.
// creating a string for the Userprofile (either C:\Admin or whatever)
String userprofile = System.getenv("USERPROFILE");
BufferedWriter writer = null;
try {
//create a temporary file
File logFile = new File(userprofile+"\\Desktop\\temp.bat");
writer = new BufferedWriter(new FileWriter(logFile));
// Here comes the lines for the batch file!
// First line is #echo off
// Next line is the directory of our file
// Then we open our file in that directory and exit the cmd
// To seperate each line, please use \r\n
writer.write("cd %ProgramFiles(x86)%\\SOME_FOLDER \r\nstart xyz.bat \r\nexit");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// Close the writer regardless of what happens...
writer.close();
} catch (Exception e) {
}
}
// running our temp.bat file
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec("cmd /c start \"\" \""+userprofile+"\\Desktop\\temp.bat" );
pr.getOutputStream().close();
} catch (IOException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
// deleting our temp file
File databl = new File(userprofile+"\\Desktop\\temp.bat");
databl.delete();
The following is working fine:
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);
This code will execute two commands.bat that exist in the path C:/folders/folder.
Runtime.getRuntime().exec("cd C:/folders/folder & call commands.bat");
import java.io.IOException;
public class TestBatch {
public static void main(String[] args) {
{
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\temp\\runtest.bat"};
Process p = Runtime.getRuntime().exec(command);
} catch (IOException ex) {
}
}
}
}
To expand on #Isha's anwser you could just do the following to get the returned output (post-facto not in rea-ltime) of the script that was run:
try {
Process process = Runtime.getRuntime().exec("cmd /c start D:\\temp\\a.bat");
System.out.println(process.getText());
} catch(IOException e) {
e.printStackTrace();
}

Process launched from Java code doesn't return

This is my code :
Process p1;
try {
p1 = Runtime.getRuntime().exec( "utils/a.out < utils/test_c2.txt > utils/result.txt" );
p1.waitFor();
} catch ( Exception e ) {
System.out.println("Something went bad!");
}
I've read that there should be a problem with the input buffer size, but in this case, all the output from the launched process is redirected to " utils/result.txt", so the launched process should not reach deadlock. When I run the same command from terminal it works. Maybe it would be helpful to describe what is "a.out". I obtained it from a flex file as follows:
$ flex rulex.lex
$ gcc lex.yy.c -lfl
Any help would be appreciated.
The subprocess is waiting to read data on stdin. Java does not launch the subprocess within a shell, so no pipes are available. You need to make your subprogram take files as arguments and open the files itself. Another option is to start a shell (like bash) and tell it to run the program, then the piping of files will work.

How to execute cd commands using java Runtime in a single cmd window

I need to execute the following Change directories commands into the cmd prompt, but using java to execute them. the dir command works fine , but not the cd ones. I have to execute them in a single cmd windows
cd inputDir
dir
cd outputDir
inputDir and outputDir are directories from the windows.
Java Snippet:
ArrayList<String> dosCommands = new ArrayList<String>();
Process p;
for (int i=0;i< dosCommands.size();i++){
p=Runtime.getRuntime().exec("cmd.exe /c "+dosCommands.get(i));
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
line=reader.readLine();
}
}
UPDATE
Changing the argument to cmd.exe /k instead of /c
p=Runtime.getRuntime().exec("cmd.exe /k "+dosCommands.get(i));
I had to remove the
p.waitFor();
method, because I was getting stucked in it.
Doing so, know I do get stucked in the
line.reader.readLine();
use
cmd.exe /K
Not
cmd.exe /c
You can find more about cmd params here
With /c, cmd finishes and exit. With /k, it does not exit.
__UPDATE__
What I mean is as follows:
cd inputDir
dir
cd outputDir
exit
Pay attention to the last line please.
__UPDATE 2__
Please use something similar in your code to find out what is the current working directory, according to running process:
public class JavaApplication1 {
public static void main(String[] args) {
System.out.println("Working Directory = " +
System.getProperty("user.dir"));
}
}
After that, let's make sure that the folders you are trying to cd to exists in that folder.
Try this experiment: Open a command window (using your mouse and/or keyboard, not with code). Now change to a different directory, with a command like cd \ or cd C:\Windows.
Then open a second command window. What is its current directory? Did it remember what you did in the first command window?
It didn't, because each time you run cmd.exe you are starting a new process, with its own current directory state.
In your code, you are executing a new cmd.exe process in each iteration of your for-loop. Each time you start a new cmd.exe, it has no awareness of what the current directory may be in other cmd.exe instances.
You can set the current directory in which a process executes:
String inputDir = "C:\\Users\\eleite\\Workspace\\RunCmd\\Petrel_Logs";
p = Runtime.getRuntime().exec("cmd.exe /c " + dosCommands.get(i),
null, inputDir);
If you want to
create process simulating console
and make this console execute few commands
and after these commands are executed continue code from main thread
then try this code
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/k");
pb.redirectOutput(Redirect.INHERIT);//redirect process output to System.out
pb.redirectError(Redirect.INHERIT);//redirect process output to System.err
Process p = pb.start();
try(PrintWriter pw = new PrintWriter(new OutputStreamWriter(p.getOutputStream()), true)){
pw.println("dir");//execute command 1, for instance "dir"
pw.println("ver");//execute command 2, for instance "ver"
//... rest of commands
pw.println("exit");//when last command finished, exit console
}
p.waitFor();//this will make main thread wait till process (console) will finish (will be closed)
//here we place rest of code which should be executed after console after console process will finish
System.out.println("---------------- after process ended ----------------");
So if you want list of commands you want to execute simply place them here:
try(PrintWriter pw = new PrintWriter(new OutputStreamWriter(p.getOutputStream()), true)){
//here and execute them like
for (String command : dosCommands){
pw.println(command);
}
pw.println("exit");//when last command finished, exit console
}

Shell script not running R (Rhipe) program from Java code

I have a simple shell script which looks like this:
R --vanilla<myMRjob.R
hadoop fs -get /output_03/ /home/user/Desktop/hdfs_output/
This shell script runs myMRjob.R, and gets the output from hdfs to local file system. It executes fine from terminal.
When i am trying to run shell script from java code, i am unable to launch the MapReduce job i.e. the first line isn't getting executed. While "hadoop fs -get .." line is running fine through Java code.
Java code which i used is:
import java.io.*;
public class Dtry {
public static void main(String[] args) {
File wd = new File("/home/dipesh/");
System.out.println("Working Directory: " +wd);
Process proc = null;
try {
proc = Runtime.getRuntime().exec("./Recomm.sh", null, wd);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The reason behind this whole exercise is that i want to trigger and display the result of the myMRjob.R in JSP.
Please help!
The reason your shell script isn't running from the exec call is because shell scripts are really just text files and they aren't native executables. It is the shell (Bash) that knows how to interpret them. The exec call is expecting to find a native executable binary.
Adjust your Java like this in order to call the shell and have it run your script:
proc = Runtime.getRuntime().exec("/bin/bash Recomm.sh", null, wd);
When you called hadoop directly from Java, it is a native executable and that's why it worked.

Categories