I am trying to execute my batch file in java with the following code
String Extraction="cmd.exe /c start C:\\task\\Extracting.bat ";
Runtime.getRuntime().exec(Extraction);
System.out.println("Extracted...");
Here, I want to execute the print statement after execution of the batch file.
But if run the above code, first it opens the command prompt and runs the batch file, and it suddenly execute the print statement before batch file runs. help me to solve this problem.
One more thing that is worth a try is the following. It waits for execution
String Extraction="cmd.exe /c start C:\\task\\Extracting.bat ";
//Runtime.getRuntime().exec(Extraction);
final Process p = new ProcessBuilder("cmd.exe", "/c", "start /WAIT C:\\task\\Extracting.bat").redirectErrorStream(true).start();
p.waitFor();
System.out.println("Job done!!");
To run that command from a Java application using my new code, we'd first build and then exec the command like this:
// build my command as a list of strings
List<String> command = new ArrayList<String>();
command.add("ls");
command.add("-l");
command.add("/var/tmp");
// execute my command
SystemCommandExecutor commandExecutor = new SystemCommandExecutor(command);
int result = commandExecutor.executeCommand();
// get the output from the command
StringBuilder stdout = commandExecutor.getStandardOutputFromCommand();
StringBuilder stderr = commandExecutor.getStandardErrorFromCommand();
// print the output from the command
System.out.println("STDOUT");
System.out.println(stdout);
System.out.println("STDERR");
System.out.println(stderr);
Resource Link:
Java exec - execute system processes with Java ProcessBuilder and
Process (part 1)
Java exec - execute system processes with Java ProcessBuilder and
Process (part 2)
Retrieving Details About Batch Jobs
When a batch job is submitted, the batch runtime creates an instance of JobExecution to track it. JobExecution has methods to obtain various details such as the job start time, job completion time, job exit status, and so on. To obtain the JobExecution for an execution ID, you can use the JobOperator.getJobExecution(executionId) method.
package javax.batch.runtime;
public interface JobExecution {
long getExecutionId();
java.lang.String getJobName();
javax.batch.runtime.BatchStatus getBatchStatus();
java.util.Date getStartTime();
java.util.Date getEndTime();
java.lang.String getExitStatus();
java.util.Date getCreateTime();
java.util.Date getLastUpdatedTime();
java.util.Properties getJobParameters();
}
Role of java here is to invoke cmd then it is upto OS to execute the instructions written in batch file:
You can check below code: Process handle will be returned by exec method.
By using waitFor() it waits for subprocess to finish and then returns exit code.
It will only return 1 when there is problem in path, otherwise 0 for success.
public class TestMe2 {
public static void main(String[] args) {
Process p=null;
String Extraction="cmd.exe /c start C:\\hello.bat ";
try {
p=Runtime.getRuntime().exec(Extraction);
System.out.println(p.waitFor());
} catch (Exception er) {
er.printStackTrace();
}finally{
}
}
}
Related
I'm using ProcessBuilder to run Postgres SQL scripts and my process seems to hang, because I'm not getting the exit value.
My code has a test method that loads and executes certain SQL files.
I then run some individual queries before executing the script file whose operations I want to test on.
#Test
public void test340() throws Exception {
String filePath = testFilePath; // Script file I want to test
TreeSet<Path> set = getFilePaths();
for (Path file : set) { // Run previous scripts to setup the db
loadFileAndExecuteSQL(file.toString());
}
preCondition340(); // Run some inserts
loadFileAndExecuteSQL(testFilePath); // Now load the script file I need to test
postCondition340(); // Run some other queries to verify resultset
}
public void loadFileAndExecuteSQL(String scriptFilePath) throws Exception {
String command = String.format("psql -v ON_ERROR_STOP=1 --host %s --port %s --dbname %s --file %s",
"localhost", "5432", dbName, scriptFilePath);
List<String> commands = Arrays.asList(command.split("\\s+"));
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
final Process process = pb.start();
if(!process.waitFor(10000, TimeUnit.MILLISECONDS)) {
process.destroy();
}
System.out.println("Executing command " + command + process.exitValue());
}
The process seems to hang on my second call to loadFileAndExecuteSQL() Could anyone explain why this is happening and suggest how I can make sure this does not happen? Thanks.
I've got some code that uses Runtime.exec() to run an external .jar (built as an IzPack installer).
If I run this external.jar from the command line like so:
java -jar external.jar
Then the command prompt does not return control until the application is finished. However, if I run external.jar from within some java class, using:
Process p = Runtime.getRuntime().exec("java -jar external.jar");
int exitCode = p.waitFor();
System.out.println("Process p returned: " + exitCode);
Then p returns almost instantly with a success code of 0, despite external.jar having not yet completed execution (i've also tried this via the ProcessBuilder route of external file execution).
Why does it wait to return from the command line, but not when executed from within another java program?
I've also set up 3 jars, A, B and C where A calls B which calls C (using Runtime.exec()), where C Thread.sleeps for 10 seconds, as a simple test, and as expected, A doesn't return until 10 seconds after it runs.
I figure this is probably some kind of a threading issue with external.jar where execution is being handed over from one thing to another, but given that it works directly from the command line i kind of expected to see the same behaviour (perhaps naively) when called from within another java program.
I've tested this on Windows and Ubuntu with Java 6.
Thanks!
another possible way to achieve this might be to capture the output of the process and wait for it to finish.
For example:
Process tr = Runtime.getRuntime().exec( new String[]{"wkhtmltopdf",mainPage,mainPagePDF});
BufferedReader stdOut=new BufferedReader(new InputStreamReader(tr.getInputStream()));
String s;
while((s=stdOut.readLine())!=null){
//nothing or print
}
Normally the output stream is tr.getInputStream() but depending on the program you are executing the process output stream migh be:
tr.getInputStream()
tr.getErrorStream()
tr.getOutputStream()
By doing this while loop you force your program to wait the process to finish.
You can use Process Builder....
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "/fielname.jar");
Process p = pb.start();
p.waitFor();
Are you spawning a new thread to handle the spawning of the process? If so the origional program will continue to operate independently of the spawned process and therefore waitFor() will only work on the new process and not the parent.
Process.waitFor() is useless for some native system command.
You need to get the process's output to determine if it is returned.
I wrote a sample code for you
/**
*
* #param cmdarray command and parameter of System call
* #param dir the directory execute system call
* #param returnImmediately true indicate return after system call immediately;
* false otherwise.
* if set true, the returned call result does not have reference value
* #return the return code of system call , default is -1
*/
public static int systemCall(String[] cmdarray,File dir,boolean returnImmediately)
{
int result = -1;
try {
Process p = Runtime.getRuntime().exec(cmdarray,null,dir);
if(!returnImmediately)
{
java.io.InputStream stdin = p.getInputStream();
java.io.InputStreamReader isr = new java.io.InputStreamReader(stdin);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
String line = null;
while ( (line = br.readLine()) != null)
System.out.println(line);
}
try{result = p.exitValue();}
catch(Exception ie){;}
} catch (IOException e) {
e.printStackTrace();}
return result;
}
public static void main(String[] argc){
String[] cmdarray = {"jar","cvf","s2.jar","*"};
File dir = new File("D:\\src\\struts-2.3.1");
int k = systemCall(cmdarray,dir,true);
System.out.println("k="+k);
}
I had the same problem using processs to execute some software using the console, and i just solved it using process.waitFor()
For me it worked perfectly.
try{
Process tr = Runtime.getRuntime().exec( new String[]{ "wkhtmltopdf",frontPage,frontPagePDF});
tr.waitFor();
} catch (Exception ex) {
EverLogger.logEntry("Error al pasar a PDF la portada", "error", "activity");
return;
}
some more code here.
I have written a shell script for automatic
1) start of hadoop services (namenode,datanode,jobtracker,tasktracker,secondary namenode),
2) dropping all tables from hive
3) again importing all tables in hive from SQL SERVER
And I am calling this shel script from java. Below is the code of Shell Script and Java Code
Shell Script:
export HADOOP_HOME=/home/hadoop/hadoop-0.20.2-cdh3u2/
export HIVE_HOME=/home/hadoop/hive-0.7.1/
export SQOOP_HOME=/home/hadoop/sqoop-1.3.0-cdh3u1/
export MSSQL_CONNECTOR_HOME=/home/hadoop/sqoop-sqlserver-1.0
export HBASE_HOME=/home/hadoop/hbase-0.90.1-cdh3u0
export ZOOKEEPER_HOME=/home/hadoop/zookeeper-3.3.1+10
export SQOOP_CONF_DIR=/home/hadoop/sqoop-1.3.0-cdh3u1/conf/
/home/hadoop/hadoop-0.20.2-cdh3u2/bin/hadoop/start-all.sh
/home/hadoop/hadoop-0.20.2-cdh3u2/bin/hadoop -rmr /user/hadoop/*
/home/hadoop/hive-0.7.1/bin/hive -e 'show tables' > TablesToDelete.txt
while read line1
do
echo 'drop table '$line1
/home/hadoop/hive-0.7.1/bin/hive -e 'drop table '$line1
done < TablesToDelete.txt
while read line
do
echo $line" ------------------------------"
/home/hadoop/sqoop-1.3.0-cdh3u1/bin/sqoop-import --connect 'jdbc:sqlserver://192.168.1.1;username=abcd;password=12345;database=HadoopTest' --table line --hive-table $line --create-hive-table --hive-import -m 1 --hive-drop-import-delims --hive-home /home/hadoop/hive-0.7.1 --verbose
done < /home/hadoop/sqoop-1.3.0-cdh3u1/bin/tables.txt
Java Code:
public class ImportTables
{
public static void main(String arsg[])
{
PrintWriter pw=null;
try
{
Formatter formatter = new Formatter();
String LogFile = "Log-"+ formatter.format("%1$tm%1$td-%1$tH%1$tM%1$tS", new Date());
File f=new File("/home/hadoop/"+LogFile);
FileWriter fw1=null;
pw=new PrintWriter(f);
String cmd = "/home/hadoop/sqoop-1.3.0-cdh3u1/bin/TablesToImport.sh"; // this is the command to execute in the Unix shell
// create a process for the shell
ProcessBuilder pb = new ProcessBuilder("bash", "-c", cmd);
pb.redirectErrorStream(true); // use this to capture messages sent to stderr
Process shell = pb.start();
InputStream shellIn = shell.getInputStream(); // this captures the output from the command
int shellExitStatus = shell.waitFor();
// wait for the shell to finish and get the return code
// at this point you can process the output issued by the command
// for instance, this reads the output and writes it to System.out:
int c;
while ((c = shellIn.read()) != -1)
{
System.out.write(c);
}
// close the stream
shellIn.close();
}
catch(Exception e)
{
e.printStackTrace();
e.printStackTrace(pw);
pw.flush();
System.exit(1);
}
}
}
But as I run the program I see nothiing on the console, and program remains in running mode.
And If I put the following code ion shell script:
/home/hadoop/hive-0.7.1/bin/hive -e 'show tables' > TablesToDelete.txt
while read line1
do
echo 'drop table '$line1
/home/hadoop/hive-0.7.1/bin/hive -e 'drop table '$line1
done < TablesToDelete.txt
Then the output come as:
Cannot find hadoop installation: $HADOOP_HOME must be set or hadoop must be in the path
What is the problem in my program/script? Where and How to set HADOOP_HOME and all that path in my script?
The call to waitFor is a blocking call, just as the name implies. It halts further execution until the process is done. But since your code is also the sink for the process's stdout, the whole thing blocks. Just move the waitFor to after you've processed the script's output.
I am wondering is there any way to execute following shell script, which waits for user input using java's Runtime class?
#!/bin/bash
echo "Please enter your name:"
read name
echo "Welcome $name"
I am using following java code to do this task but it just shows blank console.
public class TestShellScript {
public static void main(String[] args) {
File wd = new File("/mnt/client/");
System.out.println("Working Directory: " +wd);
Process proc = null;
try {
proc = Runtime.getRuntime().exec("sudo ./test.sh", null, wd);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thing is when I execute above program, I believed it will execute a shell script and that shell script will wait for user input, but it just prints current directory and then exits. Is there any way to do this or it is not possible at all in java?
Thanks in advance
The reason it prints the current dir and exits is because your java app exits. You need to add a (threaded) listener to the input and error streams of your created process, and you'll probably want to add a printStream to the process's output stream
example:
proc = Runtime.getRuntime().exec(cmds);
PrintStream pw = new PrintStream(proc.getOutputStream());
FetcherListener fl = new FetcherListener() {
#Override
public void fetchedMore(byte[] buf, int start, int end) {
textOut.println(new String(buf, start, end - start));
}
#Override
public void fetchedAll(byte[] buf) {
}
};
IOUtils.loadDataASync(proc.getInputStream(), fl);
IOUtils.loadDataASync(proc.getErrorStream(), fl);
String home = System.getProperty("user.home");
//System.out.println("home: " + home);
String profile = IOUtils.loadTextFile(new File(home + "/.profile"));
pw.println(profile);
pw.flush();
To run this, you will need to download my sourceforge project: http://tus.sourceforge.net/ but hopefully the code snippet is instructive enough that you can just adapt to J2SE and whatever else you are using.
If you use a Java ProcessBuilder you should be able to get the Input, Error and Output streams of the Process you create.
These streams can be used to get information coming out of the process (like prompts for input) but they can also be written to to put information into the process directly too. For instance:
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
String line;
while(true){
line = reader.readLine();
//...
That'll get you the output from the process directly. I've not done it myself, but I'm pretty sure that process.getOutputStream() gives you something that can be written to directly to send input to the process.
The problem with running interactive programs, such as sudo, from Runtime.exec is that it attaches their stdin and stdout to pipes rather than the console device they need. You can make it work by redirecting the input and output to /dev/tty.
You can achieve the same behaviour using the new ProcessBuilder class, setting up the redirection using ProcessBuilder.Redirect.INHERIT.
Note sure at all you can send input to your script from Java. However I very strongly recommend to have a look at Commons Exec if you are to execute external scripts from Java:
Commons Exec homepage
Commons Exec API
Could you please help me to resolve this issue.
I have a Java code which runs the rsync command using Runtime object.
I am running the below code at source machine, If there is any rsync connectivity problem during sync at target machine, the code should receive exit value, but that is not happening now.
String rsyncCommand = "rsync –abv <source> <remoteAddr:dest>"
Runtime rt = Runtime.getRuntime ();
rt.exec(rsyncCommand);
To give you more details:
When I run the rsync command directly(not through java code) in source machine and if I kill the rsync process at target machine using kill -9 option during sync, the rsync process at source will exit with exit message.
But if I run the rsync through my java code and if I kill the process during the sync at target, it is not receiving any exit message. The java and rsync process are still in running mode. But not doing any tasks.
What is the difference in running the command through java and directly through command prompt?
Any one has similar kind of problem with rsync, do we have any other options to run the rsync through java, I tried with “ProcessBuilder” as well.
Please provide me some pointers to solve this issue.
Thanks for the response, i gave only sample code, below is the complete code which i am using in my java.
Runtime rt = Runtime.getRuntime();
Process proc = null;
try {
proc = rt.exec(rsyncCommand);
InputStream stderr = proc.getErrorStream();
InputStreamReader isrErr = new InputStreamReader(stderr);
BufferedReader brErr = new BufferedReader(isrErr);
InputStream stdout = proc.getInputStream();
InputStreamReader isrStd = new InputStreamReader(stdout);
BufferedReader brStd = new BufferedReader(isrStd);
String val = null;
while ((val = brStd.readLine()) != null) {
System.out.println(val);
}
while ((val = brErr.readLine()) != null) {
System.out.println(val);
}
int exitVal = proc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
if you do this and the process is not finished yet you will not receive exit value
Process process = rt.exec(rsyncCommand);
int exitValue = process.exitValue();
instead you should use
int exitValue = process.waitFor()
then the thread will wait until the process returns exit value
Your invocation of exec() is incorrect, it should specify the parameters directly, something like:
Runtime rt = Runtime.getRuntime ();
rt.exec(new String[]{"rsync", "-abv", "<source>", "<remoteAddr:dest>"});
exec doesn't do any parsing of the command line, so it's trying to exec a command called "rsync –abv " (as a single string)