Run cmd commands through Java
Asked Answered
P

15

85

I found several code snippets for running cmd commands through a Java class, but I wasn't able to understand it.

This is code for opening the cmd

public void excCommand(String new_dir){
    Runtime rt = Runtime.getRuntime();
    try {
        rt.exec(new String[]{"cmd.exe","/c","start"});

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

And I found some other links for adding other commands such as cd http://www.coderanch.com/t/109753/Linux-UNIX/exec-command-cd-command-java

How to open the command prompt and insert commands using Java?

Can anyone help me to understand how to cd a directory such as:

 cd C:\Program Files\Flowella

then run other commands on that directory?

Puddle answered 17/3, 2013 at 17:51 Comment(1)
There is some code here - viralpatel.net/blogs/…Universalize
Q
163

One way to run a process from a different directory to the working directory of your Java program is to change directory and then run the process in the same command line. You can do this by getting cmd.exe to run a command line such as cd some_directory && some_program.

The following example changes to a different directory and runs dir from there. Admittedly, I could just dir that directory without needing to cd to it, but this is only an example:

import java.io.*;

public class CmdTest {
    public static void main(String[] args) throws Exception {
        ProcessBuilder builder = new ProcessBuilder(
            "cmd.exe", "/c", "cd \"C:\\Program Files\\Microsoft SQL Server\" && dir");
        builder.redirectErrorStream(true);
        Process p = builder.start();
        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while (true) {
            line = r.readLine();
            if (line == null) { break; }
            System.out.println(line);
        }
    }
}

Note also that I'm using a ProcessBuilder to run the command. Amongst other things, this allows me to redirect the process's standard error into its standard output, by calling redirectErrorStream(true). Doing so gives me only one stream to read from.

This gives me the following output on my machine:

C:\Users\Luke\StackOverflow>java CmdTest
 Volume in drive C is Windows7
 Volume Serial Number is D8F0-C934

 Directory of C:\Program Files\Microsoft SQL Server

29/07/2011  11:03    <DIR>          .
29/07/2011  11:03    <DIR>          ..
21/01/2011  20:37    <DIR>          100
21/01/2011  20:35    <DIR>          80
21/01/2011  20:35    <DIR>          90
21/01/2011  20:39    <DIR>          MSSQL10_50.SQLEXPRESS
               0 File(s)              0 bytes
               6 Dir(s)  209,496,424,448 bytes free
Quadrivium answered 17/3, 2013 at 18:23 Comment(12)
Thanks A lot..:) I put another command after the cd i want to execute it on the current directory,it uses some android commands,but it gives me android' is not recognized as an internal or external command,Although it works on the cmd and i added the paths to the environment variables.Puddle
That sounds to me like a PATH issue. Try printing out the value of the PATH environment variable to see whether it contains the path to the Android commands you mention. (Use System.getenv("PATH") to get its value.) You don't say how you're running your Java code (from a command prompt, from an IDE, in a web app, ...), so I can't say what you could do to fix this apparent PATH issue.Quadrivium
@LukeWoodward - Thanks. Can you please explain what these string parameters mean - "/c" and "cd \"C:\\Program Files\\Microsoft SQL Server\" && dir" ? I am actually trying to execute an svn command svn log --limit 1 http://svn.repo1.com/trunk/app from C:\Windows\system32. Please help me to get this right.Universalize
I tried my luck and found out how to do it - ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", my_svn_code); It works, but I don't know how it works.Universalize
@Steam: cmd.exe is the Command Prompt. /c tells the Command Prompt to run the rest of the line and then exit. Using a Command Prompt allows me to change directory - cd is built in to the Command Prompt, there's no cd.exe - and also to chain together two commands using &&.Quadrivium
This helped me with Jenkins groovy console script. Thank you so much!Lidda
@LukeWoodward .. can we run ( git-pull or git push ) long running task from shell script without opening cmd.exe, actually i dont black command_promt scree, ( i want it to run like background service )Aleida
@TusharPandey: why shell out to git when you could use a Java interface to Git such as JGit?Quadrivium
@LukeWoodward .. i agree but i want to use a script, and little bit confused .... that, will JGIT be able to run this script ( https://mcmap.net/q/14072/-check-if-pull-needed-in-git ) this script is just a exampleAleida
@TusharPandey: if you want an answer to your question, please ask a separate question.Quadrivium
@LukeWoodward Hi Luke, Could you please provide the same command to execute in ubuntu OS.Ride
"cmd.exe", "/c" it is for Windows. And for other O.S.?Rosemaria
B
19

You can try this:-

Process p = Runtime.getRuntime().exec(command);
Bey answered 17/3, 2013 at 17:53 Comment(2)
Perhaps because you're using Runtime.getRuntime().exec(...) instead of a ProcessBuilder? Personally, I regard Runtime.getRuntime().exec(...) as deprecated. (It wasn't me that downvoted, though.)Quadrivium
I'm not the downvoter, but -- your code is almost exactly the same as the code the OP already has. It will not solve whatever problem the OP is currently having.Yuu
M
10

If you want to perform actions like cd, then use:

String[] command = {command_to_be_executed, arg1, arg2};
ProcessBuilder builder = new ProcessBuilder(command);
builder = builder.directory(new File("directory_location"));

Example:

String[] command = {"ls", "-al"};
ProcessBuilder builder = new ProcessBuilder(command);
builder = builder.directory(new File("/ngs/app/abc"));
Process p = builder.start();

It is important that you split the command and all arguments in separate strings of the string array (otherwise they will not be provided correctly by the ProcessBuilder API).

Misteach answered 13/12, 2014 at 22:59 Comment(0)
B
9

Here is a more complete implementation of command line execution.

Usage

executeCommand("ls");

Output:

12/27/2017 11:18:11:732: ls
12/27/2017 11:18:11:820: build.gradle
12/27/2017 11:18:11:820: gradle
12/27/2017 11:18:11:820: gradlew
12/27/2017 11:18:11:820: gradlew.bat
12/27/2017 11:18:11:820: out
12/27/2017 11:18:11:820: settings.gradle
12/27/2017 11:18:11:820: src

Code

private void executeCommand(String command) {
    try {
        log(command);
        Process process = Runtime.getRuntime().exec(command);
        logOutput(process.getInputStream(), "");
        logOutput(process.getErrorStream(), "Error: ");
        process.waitFor();
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

private void logOutput(InputStream inputStream, String prefix) {
    new Thread(() -> {
        Scanner scanner = new Scanner(inputStream, "UTF-8");
        while (scanner.hasNextLine()) {
            synchronized (this) {
                log(prefix + scanner.nextLine());
            }
        }
        scanner.close();
    }).start();
}

private static SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss:SSS");

private synchronized void log(String message) {
    System.out.println(format.format(new Date()) + ": " + message);
}
Bans answered 27/12, 2017 at 16:19 Comment(0)
J
4

My example (from real project)

folder — File.

zipFile, filesString — String;

        final String command = "/bin/tar -xvf " + zipFile + " " + filesString;
        logger.info("Start unzipping: {}    into the folder {}", command, folder.getPath());
        final Runtime r = Runtime.getRuntime();
        final Process p = r.exec(command, null, folder);
        final int returnCode = p.waitFor();

        if (logger.isWarnEnabled()) {
            final BufferedReader is = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line;
            while ((line = is.readLine()) != null) {
                logger.warn(line);
            }
            final BufferedReader is2 = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            while ((line = is2.readLine()) != null) {
                logger.warn(line);
            }
        }
Jocelynjocelyne answered 17/3, 2013 at 18:8 Comment(0)
G
4

Try this:

Process runtime = Runtime.getRuntime().exec("cmd /c start notepad++.exe");
Greenstone answered 3/7, 2016 at 22:32 Comment(0)
S
3

The easiest way would be to use Runtime.getRuntime.exec().

For example, to get a registry value for the default browser on Windows:

String command = "REG QUERY HKEY_CLASSES_ROOT\\http\\shell\\open\\command";
try
{
    Process process = Runtime.getRuntime().exec(command);
} catch (IOException e)
{
    e.printStackTrace();
}

Then use a Scanner to get the output of the command, if necessary.

Scanner kb = new Scanner(process.getInputStream());

Note: the \ is an escape character in a String, and must be escaped to work properly (hence the \\).


However, there is no executable called cd, because it can't be implemented in a separate process.

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.

Easiest way for your command:

System.setProperty("user.dir", "C:\\Program Files\\Flowella");
Sclerometer answered 17/3, 2013 at 17:53 Comment(5)
where should i add this line ,do you mean Runtime.getRuntime().exec("cd what?"); can you give me an example for the cd command.Puddle
Edited my answer to hopefully add some clarity.Sclerometer
thank you ,,but i'm getting java.io.IOException: Cannot run program "cd": CreateProcess error=2, The system cannot find the file specified at java.lang.ProcessBuilder.start(Unknown Source)Puddle
@Puddle See my revised answer as to why you can't use your specific command the way you want.Sclerometer
Re: "In a Java program you can't change your current working directory and you shouldn't need to": This is not true. See my answer.Yuu
M
2

Once you get the reference to Process, you can call getOutpuStream on it to get the standard input of the cmd prompt. Then you can send any command over the stream using write method as with any other stream.

Note that it is process.getOutputStream() which is connected to the stdin on the spawned process. Similarly, to get the output of any command, you will need to call getInputStream and then read over this as any other input stream.

Menis answered 17/3, 2013 at 18:2 Comment(0)
M
2

Stopping and Disabling a service can be done via below code:

static void sdService() {
    String[] cmd = {"cmd.exe", "/c", "net", "stop", "MSSQLSERVER"};
    try {           
        Process process = new ProcessBuilder(cmd).start();
        process.waitFor();      
        String line = null;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
                            
        line = null;
        bufferedReader = null;
        Process p = Runtime.getRuntime().exec("sc config MSSQLSERVER start= disabled");
        p.waitFor();
        bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }                   
    } catch (Exception e) {
        e.printStackTrace();
    }                   
}

Enabling and Starting a service can be done via below code

static void esService() {
    String[] cmd = {"cmd.exe", "/c", "net", "start", "MSSQLSERVER"};
                    
    try {
        Process p = Runtime.getRuntime().exec("sc config MSSQLSERVER start= auto");
        //Process p = Runtime.getRuntime().exec("sc config MSSQLSERVER start= demand");
        p.waitFor();        
        String line = null;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
                            
        line = null;
        bufferedReader = null;
        Process process = new ProcessBuilder(cmd).start();          
        process.waitFor();
        bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
                        
    } catch (Exception e) {
        e.printStackTrace();
    }               
}

Executing command from any folder can be done via below code.

static void runFromSpecificFolder() {       
    try {
        ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "cd \"C:\\Users\\himan\\Desktop\\Java_Test_Deployment\\jarfiles\" && dir");
        //processBuilder.directory(new File("C://Users//himan//Desktop//Java_Test_Deployment//jarfiles"));
        processBuilder.redirectErrorStream(true);
        Process p = processBuilder.start();
        p.waitFor();        
        String line = null;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }                
    } catch (Exception e) {
        e.printStackTrace();
    }               
}
    
public static void main(String args[]) {
    sdService();
    runFromSpecificFolder();
    esService();
}
Mcintyre answered 29/12, 2020 at 14:43 Comment(0)
Y
1

You can't run cd this way, because cd isn't a real program; it's a built-in part of the command-line, and all it does is change the command-line's environment. It doesn't make sense to run it in a subprocess, because then you're changing that subprocess's environment — but that subprocess closes immediately, discarding its environment.

To set the current working directory in your actual Java program, you should write:

System.setProperty("user.dir", "C:\\Program Files\\Flowella");
Yuu answered 17/3, 2013 at 18:12 Comment(0)
C
1
public class Demo {
    public static void main(String args[]) throws IOException {

        Process process = Runtime.getRuntime().exec("/Users/******/Library/Android/sdk/platform-tools/adb" + " shell dumpsys battery ");
        BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = null;
        while (true) {
            line = in.readLine();
            if (line == null) { break; }
            System.out.println(line);
        }
    }
}
Carrell answered 11/1, 2020 at 16:50 Comment(1)
While this code may provide a solution to OP's problem, it is highly recommended that you provide additional context regarding why and/or how this code answers the question. Code only answers typically become useless in the long-run because future viewers experiencing similar problems cannot understand the reasoning behind the solution.Craniate
S
0

The simplest and shortest way is to use CmdTool library.

new Cmd()
         .configuring(new WorkDir("C:/Program Files/Flowella"))
         .command("cmd.exe", "/c", "start")
         .execute();

You can find more examples here.

Subnormal answered 24/4, 2018 at 10:49 Comment(0)
V
0

one of the way to execute cmd from java !

public void executeCmd() {
    String anyCommand="your command";
    try {
        Process process = Runtime.getRuntime().exec("cmd /c start cmd.exe /K " + anyCommand);

    } catch (IOException e) {
        e.printStackTrace();
    }
}
Valued answered 18/3, 2019 at 2:42 Comment(0)
C
0

Here the value adder is use of ampersands to batch commands and correct format for change drive with cd.

public class CmdCommander {

public static void main(String[] args) throws Exception {
    //easyway to start native windows command prompt from Intellij

    /*
    Rules are:
    1.baseStart must be dual start
    2.first command must not have &.
    3.subsequent commands must be prepended with &
    4.drive change needs extra &
    5.use quotes at start and end of command batch
    */
    String startQuote = "\"";
    String endQuote = "\"";
    //String baseStart_not_taking_commands = " cmd  /K start ";
    String baseStart = " cmd  /K start cmd /K ";//dual start is must

    String first_command_chcp = " chcp 1251 ";
    String dirList = " &dir ";//& in front of commands after first command means enter
    //change drive....to yours
    String changeDir = " &cd &I: ";//extra & makes changing drive happen

    String javaLaunch = " &java ";//just another command
    String javaClass = " Encodes ";//parameter for java needs no &

    String javaCommand = javaLaunch + javaClass;
    //build batch command
    String totalCommand =
            baseStart +
                    startQuote +
                    first_command_chcp +
                    //javaCommand +
                    changeDir +
                    dirList +
                    endQuote;

    System.out.println(totalCommand);//prints into Intellij terminal
    runCmd(totalCommand);
    //Thread t = Thread.currentThread();
    //t.sleep(3000);
    System.out.println("loppu hep");//prints into Intellij terminal

}


public static void runCmd(String command) throws Exception {

    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(command);


}

}

Clinton answered 4/1, 2020 at 21:21 Comment(3)
Why define two vars for same quote character?Sobersided
Also FYI - the CD can be done by supplying argument to exec - as a type File - i.e. base folder.Sobersided
Well. I just wanted to make clear the litany to myself to nonthinking extent. The command can be several pages long so it is nice to see immediately where is the start and end quotes and that they are in place. CD is there just to show it can be there because it is needed in many cases. You can first execute the command in one dir and then move to another and execute other command in that directory it being your new user directory. That would be because you need to consider windows dll load order so you must know what is the current directory i.e java user dir.Clinton
R
0

(as others said) For simple commands, you can just do, eg:
Runtime.getRuntime().exec("cmd /c mkdir H:\\test\\BBB");
(cmd /c is likely needed)

However, for some complex commands, you may need to do a double cmd.exe /c cmd.exe /c,
otherwise (if you use only 1) the cmd gets silently dropped,
((or if you dont use /c or use some weird /c cmd combination pattern, cmd may freeze)),
idk why.

((How I discorve it? -- I couldnt get it work & tried mutiple time; one time accidentally duplicated the cmd & ran it & found it.))

@eg::

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class T1 {

  static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
  }

  public static void main(String[] args) throws InterruptedException, IOException {

    Process process;

    System.out.println("---"); // creates a folder `BBB`
    Runtime.getRuntime().exec("cmd /c mkdir H:\\test\\BBB");

    // System.out.println("---");
    // idk how to do `cd`

    System.out.println("---"); // list file & folder in C:\
    process = Runtime.getRuntime().exec("cmd.exe /c dir C:\\");
    System.out.println(convertStreamToString(process.getInputStream()));

    System.out.println("---"); // echo
    process = Runtime.getRuntime().exec("cmd.exe /c echo \"Some Line\"");
    System.out.println(convertStreamToString(process.getInputStream()));

    // @atten: notice the double `cmd.exe /c cmd.exe /c ` 
    // -- idk why must double - otherwise this wont execute
    System.out.println("---"); // uses mysqldump to do something 
    process = Runtime.getRuntime().exec("cmd.exe /c cmd.exe /c \"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe\" -u root -pmysql db_drawandchat_01 > \"H:\\DrawAndChatApp_db\\DrawAndChat_20230503_0134_03326.sql\"");

  }

  // Output::
  //
  // ---
  // ---
  //  Volume in drive C has no label.
  //  Volume Serial Number is 2C83-063F
  // 
  //  Directory of C:\
  // 
  // 2019/06/29  11:56    <DIR>          Intel
  // 2022/04/18  06:07    <DIR>          log
  // 2019/12/07  17:14    <DIR>          PerfLogs
  // 2023/04/22  01:13    <DIR>          Program Files
  // 2023/04/08  21:27    <DIR>          Program Files (x86)
  // 2020/12/08  00:15    <DIR>          Untitled
  // 2021/04/23  04:57    <DIR>          Users
  // 2023/04/25  09:33    <DIR>          Windows
  //                0 File(s)              0 bytes
  //                8 Dir(s)   3,268,296,704 bytes free
  // 
  // ---
  // "Some Line"
  // 
  // ---

}


update

base on my experience

ProcessBuilder with array of String as args is a much better choice.

@note::

  • use array of String as args, dont use a whole String
    otherwise the parsing is likely to be wrong.
    CreateProcess error=2, The system cannot find the file specified

  • remove unnecessary double quotes (eg: the ones around a path of a exec)
    (since you are using array, the space_in_path cmd problem is kinda eliminated // actually, not really, see update below -> still use [a double cmd.exe /c cmd.exe /c]).
    Java - ProcessBuilder command arguments with spaces and double-quotes fails

  • the array is separated base on the "exec & flag & arg & path"
    -- normally, wherever you have a space, you separate there (though, not on the paths)

    • sometimes you dont separate the flag and arg (if there is no space between them), eg: -pPASSWORD

@eg:: [String Cmd to Array Cmd in ProcessBuilder]

(following code worked before, but didnt test after some minor modifications)

  public class T1 {

    public static void main(String[] args) throws InterruptedException, IOException {

      String cmdStr_loadFile = "cmd.exe /c cmd.exe /c "
                               + "\"C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe\" "
                               + "-u root "
                               + "-pmysql "
                               + "--database db_drawandchat_02 "
                               + "< "
                               + "\"H:\\DrawAndChatApp_db\\DrawAndChat_test.sql\"";

      ArrayList<String> cmdArr_loadFile = new ArrayList<>(Arrays.asList("cmd", "/c",
          "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysql.exe",
          "-u", "root",
          "-pmysql",
          "--database", "db_drawandchat_02",
          "<",
          "H:\\DrawAndChatApp_db\\DrawAndChat_test.sql"));

      try {
        //      Process process = Runtime.getRuntime().exec(cmdStr_loadFile);

        ProcessBuilder processBuilder = new ProcessBuilder(cmdArr_loadFile);
        //      processBuilder.directory(new File("H:/"));
        processBuilder.redirectOutput(Redirect.INHERIT);
        processBuilder.redirectError(Redirect.INHERIT);
        //      processBuilder.redirectInput(Redirect.INHERIT);

        Process process = processBuilder.start();

        try {
          process.waitFor(20, TimeUnit.SECONDS);
          //        System.out.println(StringUtil.convertStreamToString(process.getInputStream()));
        } catch (InterruptedException e) {
          throw new Error(e);
        }
      } catch (IOException e) {
        throw new Error(e);
      }
    }

  }

update

The use of >"a double cmd.exe /c cmd.exe /c"
is also working in the case of >"ProcessBuilder with array of String as args"

Especially when you have space in your path -- both executable path && file path arg

@eg::

    ArrayList<String> cmdArr_saveFile = new ArrayList<>(
        Arrays.asList("cmd", "/c", "cmd", "/c",
                      "C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe",
                      "-u", "root",
                      "-pmysql",
                      "db_drawandchat_01",
                      ">",
                      "H:\\DrawAndChatApp_db\\DrawAndChat test2.sql"));
Renin answered 2/5, 2023 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.