I'm trying to create a java program that runs CMD with a specific command
dir C:\windows | java -jar C:\\Column.jar 3
When i run it manual works, but I've not been hable to run it from java.
I have read and tried every post I've seen without luck. So far my code looks like this:
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
String comand = "cmd /c start dir \"C:\\Windows\" | java -jar C:\\Column.jar 3";
Process process = Runtime.getRuntime().exec(comand);
process.waitFor();
}
}
PS: "Column.jar X" just keeps the X column (or subString using space of tab as a separator) of a String.
PS2: I think it's has something to do with the pipe or at least with the use of 2 commands at once.
I suppose you could use Conditional Execution as explained in the link or in this StackExchange Post.
I personally would run the two commands separately but then, I'm not really sure what the overall task may be.
If you want to want to execute your multiple commands from within the Command Interpreter Window (CMD), it would be something like this:
Multiple commands directly in CMD window:
cmd /C dir "C:\Windows" && java -jar "C:\Column.jar" "3"
providing of course that, the Column.jar
file is located within the root directory of drive C
. If however, you try to run this in Java with Process.exec() or ProcessBuilder, you may not be so lucky...at least I wasn't. When trying to open the Command Interpreter (CMD) Window and running both commands, the first process (command) doesn't appear to ever terminate. I'm sure I'm just missing some sort of process setting.
Multiple commands from within a Batch File:
What will work, is if you run the the commands from within a small batch file. For the sake of argument, let's name it RunBatch.bat
. It only requires the one line to open the CMD Window and run both commands:
@ECHO OFF
as the first line and hit the ENTER key;cmd /C dir "C:\Windows" && java -jar "C:\Column.jar" "3"
. Again, assuming Windows is on drive C
and Column.jar
is within
the root directory of drive C
;RunBatch.bat
in a known location (let's
use the root of drive C
).Of course you can create this batch file with code but you need to know that, it's not a good idea to create it within the root of drive C
if Windows is installed on that drive. It will require special permissions to do so and an Access Denied! message will most likely occur. Perhaps better to place it in C:\\Users\\Public\\
or somewhere better with guaranteed access rights. Just remember where it is because you will need to know the full path to that batch file.
You will also notice that the Column.jar
file being started accepts two command-line arguments where the first is the String to get a word from. The second argument is the literal word number to get and display within the Console Window. If no command-line arguments are supplied then defaults are used. The default String is: "This is a demo test String!"
and the default column (word to get) is 1
.
To create and run this batch file, you might use something like this:
// Create batch file:
String stringArgForJAR = "My dog ran up the slippery slope and slid back down!";
int desiredWordNumberArgForJAR = 6;
String cmdCommands = "cmd /C dir \"C:\\Windows\" && java -jar \"C:\\Column.jar\" "
+ "\"" + stringArgForJAR + "\" \"" + desiredWordNumberArgForJAR + "\"";
String batchFilePath = "C:\\Users\\Public\\RunBatch.bat";
try (java.io.PrintWriter writer = new java.io.PrintWriter(batchFilePath)) {
writer.println("@ECHO OFF:);
writer.print(cmdCommands);
writer.flush();
}
catch (FileNotFoundException ex) {
System.out.println(ex.getMessage());
}
// Run the created batch file....
Process process = null;
try {
String[] command = {"cmd.exe", "/C", "Start", batchFilePath};
process = Runtime.getRuntime().exec(command);
process.waitFor();
}
catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
finally {
if (process != null && process.isAlive()) {
process.destroy();
}
}
Saving run process responses Into a List:
Up to now, I assume that you want to display everything within the Command Interpreter Window, at least that is the jest I got out of your post. If you actually what to place the responses from each run process in a List Interface or String (List) and not see the Command Interpreter Window at all, then you might want to utilize something like this:
All run process responses in one List:
String directoryToList = "C:\\Windows";
String stringArgForJAR = "My dog ran up the slippery slope and slid back down!";
int desiredWordNumberArgForJAR = 6;
String command = "dir \"" + directoryToList + "\" && java -jar \""
+ "C:\\Column.jar\" \""
+ stringArgForJAR + "\" \"" +desiredWordNumberArgForJAR + "\"";
List<String> responses = runCMD(command);
// Display contents of List in Console Window:
System.out.println("All Responses:\n==============\n");
for (String strg : responses ) {
System.out.println(strg);
}
System.out.println();
Process responses in separate Lists:
String directoryToList = "C:\\Windows";
String stringArgForJAR = "My dog ran up the slippery slope and slid back down!";
int desiredWordNumberArgForJAR = 6;
String command1 = "dir \"" + directoryToList + "\"";
List<String> windowsDir = runCMD(command1);
System.out.println("Windows Directory:\n==================");
// Run Column.jar:
String command2 = "java -jar C:/Users/Devil/NetBeansProjects/Column/dist/Column.jar \""
+ stringArgForJAR + "\" \"" + desiredWordNumberArgForJAR + "\"";
System.out.println("Desired Word from String:\n=========================");
List<String> jarResponse = runCMD(command2);
// Display contents of List for command1 in Console Window:
for (String strg : windowsDir) {
System.out.println(strg);
}
System.out.println();
// Display contents of List for command2 in Console Window:
for (String strg : jarResponse) {
System.out.println(strg);
}
The runCMD() Method:
/**
* This method is specifically designed solely for running the Microsoft
* Windows CMD command prompt and having the results that would normally be
* displayed within a Command Prompt Window placed into a string ArrayList
* (List) instead.<br><br>
* <p>
* <b>Example Usage:</b><pre>
* {@code
* List<String> response = runCMD("dir \"C:/Windows\"");
* // Display the List:
* for (String str : response) {
* System.out.println(str);
* }
* }</pre>
*
* @param commandString (String) The command string to pass to the Command
* Prompt. You do not need to place "cmd" within your
* command string because it is applied automatically.
* As a matter of fact if you do it is automatically
* removed.<br>
*
* @return (List<String>) A string ArrayList containing the results of
* the processed command.
*/
public static java.util.List<String> runCMD(String commandString) {
if (commandString.toLowerCase().startsWith("cmd ")) {
commandString = commandString.substring(4);
}
java.util.List<String> result = new java.util.ArrayList<>();
Process p = null;
try {
p = Runtime.getRuntime().exec("cmd /C " + commandString);
try (java.io.BufferedReader in = new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()))) {
String line;
while ((line = in.readLine()) != null) {
result.add(line);
}
}
p.waitFor();
return result;
}
catch (java.io.IOException | InterruptedException ex) {
javax.swing.JOptionPane.showMessageDialog(null, "<html>IO Error during processing of RunCMD()!"
+ "<br><br>" + ex.getMessage() + "</html>",
"runCMD() Method Error", javax.swing.JOptionPane.WARNING_MESSAGE);
return null;
}
finally {
if (p != null && p.isAlive()) {
p.destroy(); // Kill the Process in case of abnormal process termination through 'waitFor()'.
}
}
}
The Column.jar application:
public class Column {
public static void main(String[] args) {
// The default string to get a word from:
String defaultString = "This is a demo test String!";
// Get the number of words within the default string:
int numberOfWords = defaultString.split("\\s+").length;
// Default column number:
int defaultColomn = 1;
System.out.println();
// Check for a command-line argument:
// Has Command-Line arguments been supplied? This app will accept 2 arguments
if (args.length > 0) {
// Yes...
/* Is there a a second command-line argument? If so, we
want to process this first because we need to get a
new number of words count for conditions when checking
validity of the first supply argument (Word number). */
if (args.length >= 1) {
// If the supplied argument is empty - ignore it and use default!
if (!args[0].trim().isEmpty()) {
// Desired string to process validation has passed!
defaultString = args[0];
// Update the numberOfWords variable based on non-default string:
numberOfWords = defaultString.split("\\s+").length;
}
}
if (args.length == 2) {
// Validate the passed command-line argument:
if (!args[1].matches("\\d+") || Integer.parseInt(args[1]) < 1
|| Integer.parseInt(args[1]) > numberOfWords) {
System.out.println("Invalid Command-Line Argument (Argument: -> " + args[1] + ")! Either the");
System.out.println("supplied argument is not a valid number or the number is");
System.out.println("Out Of Bounds! - Only values of 1 to " + numberOfWords + " are permitted!");
System.out.println();
return;
}
// Desired word number Validation passed!
defaultColomn = Integer.parseInt(args[1]);
}
}
// No... Use default column number (1):
System.out.println("String: -> \"" + defaultString + "\"");
String[] words = defaultString.trim().replaceAll("\\p{Punct}", "").split("\\s+");
System.out.println("The word in literal column " + defaultColomn
+ " is -> \"" + words[defaultColomn - 1] + "\"");
}
}