How to print commands to bat/cmd file using Java? I have created a method that opens this bat file and now the program should write commands to this bat file. For instance, I have a string variable "Command" and the program must write this command to bat file.
Here I attach the code.
private static void openBat(){
File file = new File(lockerPath);
try {
if (file.exists()) {
Process pro = Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + lockerPath);
pro.waitFor();
} else {
System.out.println("file does not exist");
}
} catch (Exception e) {
System.out.println(e);
}
}
This is the code to open bat file, and the next code is to write commands:
private static void printing(int password ){
try {
ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/C", lockerPath);
Process process = processBuilder.start();
process.waitFor();
List<String> commands = new ArrayList<>();
commands.add(String.valueOf(password));
processBuilder.command(commands);
}catch (Exception ex){
ex.printStackTrace();
}
}
It doesn't write anything to the file.
I will be very grateful for your help.
I still don't think I completely understand your question. If you just want to simulate the user entering a value to a batch file via a java program, then the below code does that.
First I wrote a batch file.
#echo off
set /P pw=
echo You entered: %pw%
It simply waits for the user to enter a value and assigns that value to a variable named pw. After the user enters the value, the batch file displays the entered value.
Here is the java code that runs the above batch file and enters a value.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "getusrpw.bat");
try {
Process p = pb.start(); // throws java.io.IOException
BufferedReader stdout = p.inputReader();
BufferedReader stderr = p.errorReader();
BufferedWriter stdin = p.outputWriter();
stdin.write("secret");
stdin.newLine();
stdin.flush();
String output = stdout.readLine();
while (output != null) {
System.out.println("OUT> " + output);
output = stdout.readLine();
}
String error = stderr.readLine();
while (error != null) {
System.out.println("ERR> " + error);
error = stderr.readLine();
}
int exitStatus = p.waitFor(); // throws java.lang.InterruptedException
System.out.println("Process exit status = " + exitStatus);
}
catch (InterruptedException | IOException x) {
x.printStackTrace();
}
}
}
The name of the batch file is getusrpw.bat.
stdout is for reading output generated by the batch file.
stderr is for reading error output. Note that there may be no error output.
stdin is for sending input to the batch file.
Note that methods inputReader, outputWriter and errorReader were added in JDK 17. If you are using an earlier version, use methods getInputStream, getOutputStream and getErrorStream, respectively.
The Java program enters the value secret.
The Java program prints the output generated by the batch file.
When I run the above Java code, it produces the following output:
OUT> You entered: secret
Process exit status = 0
Related
The following Main.java code simply tries to simulate the following linux command:
cd /dir1/dir2
./shellScript.sh
The program below works only if the executable Main.jar sits within /dir1/dir2, not outside of /dir1/dir2. How do I modify the program below so that Main.jar can sit anywhere on the file system?
public class Main {
public static String runCmdLineProcess(String commandStr){
String returnVal = "";
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec(commandStr);
BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = b.readLine()) != null){
returnVal += line + "\n";
}
}
catch(IOException ex){
ex.printStackTrace();
}
return returnVal;
}
public static void runProcessBuilder(String scriptPath){
String[] cmd = {scriptPath};
try {
runCmdLineProcess("cd /dir1/dir2");
Runtime.getRuntime().exec(cmd);
}
catch (IOException ex){
ex.printStackTrace();
}
}
public static void main(String[] args){
runProcessBuilder("./shellScript.sh"); // <-- works if I run from inside "/dir1/dir2".
//But if I'm outside "dir2", get an error message
// saying "Cannot run program "./shellScript.sh": error = 2, No such file or directory
}
}
You should use ProcessBuilder to launch or one of the overloads of exec. You need to specify the pathname to the script and pass the same pathname as the current directory to run the script in:
File pwd = new File("/dir1/dir2");
String shell = new File(pwd, "shellScript.sh").toString();
ProcessBuilder pb = new ProcessBuilder(shell);
// No STDERR => merge to STDOUT - or call redirectError(File)
pb.redirectErrorStream(true);
// Set CWD for the script
pb.directory(pwd);
Process p = pb.start();
// Move STDOUT to the output stream (or original code to save as String)
try(var stdo = p.getInputStream()) {
stdo.transferTo(stdout);
}
int rc = p.waitFor();
I have a Python script which I am attempting to run via code in Java.
The Python script runs fine when run through a Linux terminal command on my Ubuntu virtual machine using an identical command to the one being passed through the Java script.
The Java code runs fine when running a different Python script that runs faster than the Python script I'm attempting to run..
However, despite both the Python script running fine and the Java script running fine, somehow, when I put the two together, nothing happens: The .txt file isn't updated, so the Java script prints out whatever old value it contains.
System.out.println("starting...");
try {
Process process = Runtime.getRuntime().exec("python3 /home/.../PycharmProjects/.../fraudanalysis.py abc def");
Thread.sleep(900000);
# Or try System.out.println(process.waitFor());
File file = new File("/home/.../PycharmProjects/.../output.txt");
Scanner newLineReader = new Scanner(file);
System.out.println(newLineReader.nextLine());
} catch(Exception e) {
System.out.println(e);
}
The code above should run the Python3 script at the absolute directory provided, using two arguments. The Python3 script completes after around 13 minutes and updates the output.txt file, which is then read by the Java program after waiting 15 minutes (or you can tell the thread to wait for completion-- process.WaitFor() returns 1).
def testScript():
time.sleep(780)
return_string1 = sys.argv[1]
return_string2 = sys.argv[2]
outputFile = open(os.path.dirname(os.path.abspath(__file__)) + "/output/output.txt", "w+")
outputFile.write(return_string1 + " " + return_string2)
print("Python run complete")
if __name__ == "__main__":
testScript()
The script above is a good stand-in for the Python script. If you lower the sleep time to 10 minutes for the Python script, it runs when Java sends the command. But, at the sleep times shown above, Java apparently fails to run the script, or the script run attempt ends in failure.
Additional info: the Java command is activated using a JavaFX button. The Java script has been developed in IntelliJ IDEA and the Python script was created using PyCharm.
My question is, what are possible causes for this problem, when both scripts work fine on their own?
As a simple suggestion, you should not rely on Thread.sleep method with a fixed parameter such as 15 minutes. Your data may grow or shrink and that way of proceeding is not efficient.
You could try to call the Process.waitFor() method so that when the python process is over, your thread continues.
Moreover, you could try to use ProcessBuilder that sometimes helps when facing buggy System exec cases.
Here is some code. in sub(), you can not change the python program, but for sub2() to work, you have to modify the python program so that its output is on the standard out and Java would do the redirect to the output.txt file.
public void sub() {
System.out.println("startig...");
Scanner newLineReader = null;
try {
Process process = Runtime.getRuntime().exec("python3 /home/.../PycharmProjects/.../fraudanalysis.py /home/.../PycharmProjects/.../fraudAnalysis.db 500");
process.waitFor();
File file = new File("/home/.../PycharmProjects/.../output.txt");
newLineReader = new Scanner(file);
String line;
while((line=newLineReader.nextLine())!=null) {
System.out.println(line);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}catch(InterruptedException ie) {
ie.printStackTrace();
}finally {
newLineReader.close();
}
}
public void sub2() {
ProcessBuilder pb =
new ProcessBuilder("python3",
"/home/.../PycharmProjects/.../fraudanalysis.py",
"/home/.../PycharmProjects/.../fraudAnalysis.db", "500");
File log = new File("/home/.../PycharmProjects/.../output.txt");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = null;
try {
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
try {
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
Scanner newLineReader = null;
try{
newLineReader = new Scanner(log);
String line;
while((line=newLineReader.nextLine())!=null) {
System.out.println(line);
}
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
I was able to get it to work with a small modification. I used relative file locations and TimeUnit.MINUTES.sleep(15);
package org.openjfx;
import java.io.File;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class TestWait {
public static void main(String[] args) {
System.out.println("starting...");
String dir="src/main/resources/org/openjfx/";//location of the python script
try {
System.out.println("Working Directory = " + System.getProperty("user.dir"));
//System.out.println("python3 " + dir+"fraudanalysis.py abc def");
Process process = Runtime.getRuntime().exec("python3 " + dir+"fraudanalysis.py abc def");
System.out.println(process.waitFor());
TimeUnit.MINUTES.sleep(15);
File file = new File("src/main/resources/org/openjfx/output.txt");
Scanner newLineReader = new Scanner(file);
System.out.println(newLineReader.nextLine());
} catch (Exception e) {
System.out.println(e);
}
}
}
Here is the python I used.
import sys
import time
def testScript():
return_string1 = sys.argv[1]
return_string2 = sys.argv[2]
time.sleep(780)
outputFile = open("src/main/resources/org/openjfx/output.txt", "w+")
outputFile.write(return_string1 + " " + return_string2)
print("Python run complete")
if __name__ == "__main__":
testScript()
it's a timeout error. can't be fixed. just pick between Java and Python and write everything in it. no reason to use both.
I'm doing a simple java compiler. My program is running, but if it is going to scan, it will not receive input and will freeze.
A small code from my compiler
public class ProcessBuilderMultipleCommandsExample {
static String backSlashFl = "C:\\Users\\xxA\\Desktop";
public static void main(String[] args) throws InterruptedException,
IOException {
// multiple commands
// /C Carries out the command specified by string and then terminates
ProcessBuilder pbC = new ProcessBuilder( //COMPİLE
"cmd.exe", "/c", "cd " + backSlashFl + "&& javac " + "Test" + ".java");
Process processC = pbC.start();
ProcessBuilder pb = new ProcessBuilder( //RUN
"cmd.exe", "/c", "cd " + backSlashFl + "&& java " + "Test");
Process process = pb.start();
IOThreadHandler outputHandler = new IOThreadHandler(
process.getInputStream());
outputHandler.start();
process.waitFor();
System.out.println(outputHandler.getOutput());
}
private static class IOThreadHandler extends Thread {
private InputStream inputStream;
private StringBuilder output = new StringBuilder();
IOThreadHandler(InputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
Scanner br = null;
try {
br = new Scanner(new InputStreamReader(inputStream));
String line = null;
while (br.hasNextLine()) {
line = br.nextLine();
output.append(line
+ System.getProperty("line.separator"));
}
} finally {
br.close();
}
}
public StringBuilder getOutput() {
return output;
}
}
}
I think it's working in the back, but how do I get the input part?
Here's the file I want to compile and run.
import java.awt.*;
import java.awt.event.*;
import java.util.Scanner;
public class numberScan {
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
System.out.println("Enter the number: ");
int a=scan.nextInt();
System.out.println("Number= " + a);
}
}
I'm waiting for your help.
Editted
Now when I run the GUI, the Run key is pressed. What do you think I should do?
buttonRun.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String backSlashFl = file.getAbsolutePath().replace("\\", "\\\\");
backSlashFl = backSlashFl.replace(flName + ".java", "");
try {
execute("cmd.exe", "/c", "cd " + backSlashFl + " && java " + flName);
JOptionPane.showMessageDialog(null, "Dosya çalıştı!","Bilgilendirme",
JOptionPane.INFORMATION_MESSAGE);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException ae) {
// TODO Auto-generated catch block
ae.printStackTrace();
} catch (Exception e2){
e2.printStackTrace();
}
}
});
When the GUI app runs, this run button remains.
There are several issues with the given code. I tried to squeeze it into a comment, but now decided to extend it to an answer:
The class that you want to compile is called numberScan, but obviously stored in a file called Test.java. A public class can only be stored in a file that has the same name as the class. Call the class NumberScan, and call the file NumberScan.java.
You are only trying to print the output that is provided by the input stream. But you are not printing the result that is provided by the error stream (so if there are errors, you will not see them!). Also, you only printed the output of the Process process (which is used for running the program). You did not print the output of the Process processC, which was used for compiling the program.
The reason of why you don't see any output is that the line
System.out.println(outputHandler.getOutput());
is executed before the process is finished. You used waitFor, but the output is filled by a different thread - namely, the IOThreadHandler. The getOutput method could only be called after the IOThreadHandler has finished, but if you want to continuously update the output, then this will not work.
It is not entirely clear what you want to achieve, but guessing from the code that you provided, your goal seems to be to create a program that
Compiles the given Java file
Executes the resulting Java program
Prints possible error messages and the output that is created by the program
Important: Allows interacting with the program, in the sense that it should be possible to send input to the System.in of the program.
The last two points are particularly hard to achive manually. You would have to set up threads for reading the input stream and the error stream. These would require some trickery to make sure that the data is read continuously while the program is executed. Additionally, you would have to set up a thread that forwards the data that the user enters to the Java program that is executed in its own process.
Fortunately, all this has become fairly trivial with Java 7: You can simply set an appropriate ProcessBuilder.Redirect for all the streams (namely, the redirect INHERIT), so that all the streams are mapped to the corresponding streams of the surrounding program.
Here is an example:
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.util.Arrays;
public class ProcessBuilderMultipleCommandsExample {
private static String path = "C:\\Users\\xxA\\Desktop";
public static void main(String[] args)
throws InterruptedException, IOException {
execute("cmd.exe", "/c", "cd " + path + " && javac " + "NumberScan" + ".java");
execute("cmd.exe", "/c", "cd " + path + " && java " + "NumberScan");
}
private static void execute(String ... commands)
throws IOException, InterruptedException
{
System.out.println("Executing "+Arrays.asList(commands));
ProcessBuilder processBuilder = new ProcessBuilder(commands);
processBuilder.redirectInput(Redirect.INHERIT);
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
Process process = processBuilder.start();
process.waitFor();
}
}
I am trying to untar a file on a Unix machine, using a Java batch application.
Source Code:
String fileName = "x98_dms_12";
Runtime.getRuntime().exec("gunzip "+ fileName + ".tar.gz");
System.out.println(" Gunzip:"+"gunzip "+ fileName + ".tar.gz");
Runtime.getRuntime().exec("tar -xvf "+ fileName + ".tar");
System.out.println(" Extract:tar -xvf "+ fileName + ".tar");
Problem Description:
When I run the batch program it does not (completely) work. Only the gunzip command works, converting my fileName.tar.gz to fileName.tar. But the untar command does not seem to do anything, and there is no error or exception in my log or Unix console.
When I run the same commands in a Unix prompt they work fine.
Notes:
The path of execution is correct because it converts my *.tar.gz to *.tar
I cannot use "tar -zxvf fileName.tar.gz" since the attribute "z" does not work on my system.
There is no error or exception thrown.
Please do help.
A couple of things:
The tar command will expand a file relative to your working directory, which might need to be set for your Java Process objects
You should wait for the unzip process to complete before launching into the untar process
You should process the output streams from the processes.
Here is a working example that you can extend/adapt. It uses a separate class to deal with the process output streams:
class StreamGobbler implements Runnable {
private final Process process;
public StreamGobbler(final Process process) {
super();
this.process = process;
}
#Override
public void run() {
try {
final BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (final Exception e) {
e.printStackTrace();
}
}
}
public void extractTarball(final File workingDir, final String archiveName)
throws Exception {
final String gzFileName = archiveName + ".tar.gz";
final String tarFileName = archiveName + ".tar";
final ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.directory(workingDir);
builder.command("gunzip", gzFileName);
final Process unzipProcess = builder.start();
new Thread(new StreamGobbler(unzipProcess)).start();
if (unzipProcess.waitFor() == 0) {
System.out.println("Unzip complete, now untarring");
builder.command("tar", "xvf", tarFileName);
final Process untarProcess = builder.start();
new Thread(new StreamGobbler(untarProcess)).start();
System.out.println("Finished untar process. Exit status "
+ untarProcess.waitFor());
}
}
The code below will print the output of the command executed. Check if it returns any error.
Process p = Runtime.getRuntime().exec("tar -xvf "+ fileName + ".tar");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
The problem is the commands which we give is UNIX command so it wont work in windows environment. I had written a script file to overcome this problem thanks all for you help. The Runtime.getRuntime.exec() will take some time to execute the command given so after each exec() give thread.wait(3000) to complete the process and goto next thread.
I am trying to execute .sql file from java. It runs successfully when I put exit at the end of the .sql file. Is there any possibility to run without giving exit in .sql?
Java code
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test {
private static String script_location = "";
private static String file_extension = ".sql";
private static ProcessBuilder processBuilder =null;
public static void main(String[] args) {
try {
//D:/Tset is the folder that contains the.sql files
File file = new File("D:/Tset");
File [] list_files= file.listFiles(new FileFilter() {
public boolean accept(File f) {
if (f.getName().toLowerCase().endsWith(file_extension))
return true;
return false;
}
});
for (int i = 0; i<list_files.length;i++){
script_location = "#" + list_files[i].getAbsolutePath();
//ORACLE
processBuilder = new ProcessBuilder
("sqlplus","user56/password", script_location); //ORACLE
//script_location = "-i" + list_files[i].getAbsolutePath();
// processBuilder =
new ProcessBuilder("sqlplus",
"-Udeep-Pdumbhead-Spc-de-deep\\sqlexpress-de_com",script_location);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
BufferedReader in =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String currentLine = null;
while ((currentLine = in.readLine()) != null) {
System.out.println(" " + currentLine);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
Oracle script file:
createtable.sql
createtable.sql
create table t1(empname varchar2(20),address varchar2(20))
/
create table t2(name varchar2(20),lname varchar2(20))
/
exit;
insertvalue.sql
insert into t1 values('aaaaa','chennai')
/
insert into t2 values('bbbbb','ddddd')
/
exit;
If I don't put an exit at last it simply runs the first file only. Is there a solution to this?
In your code you run the command sqlplus in a loop so you must end every command (using exit to exit sqlplus).
If you want to call many scripts on the same sqlplus instance then maybe you can create "on the fly" a script that has commands such as:
onTheFlyAcript.sql
#createtable.sql <your params>
#insertvalue.sql <your params>
exit;
So basically you can do something like:
try {
Printwriter out = new PrintWriter(new FileWriter("D:/Test/onTheFlyScript.sql"));
for (int i = 0; i<list_files.length;i++){
script_location = "#" + list_files[i].getAbsolutePath();
out.println("START script_location");
}
out.close();
} catch (IOException e){
e.printStackTrace();
}
// note that this command is not in the loop, it's just for running the new script you've created
processBuilder = new ProcessBuilder
("sqlplus","user56/password", "D:/Test/onTheFlyAcript.sql");
This will probably have to be debuged, but the idea is that instead of executing all your scripts one by one with sqlplus, you create a new script that contains the calls to all your scripts.
Now you can remove the exit sqlplus command from all your scripts since you don't need to exit sqlplus (only in onTheFlyScript.sql)