通过Java运行cmd命令

82

我找到了几个通过Java类运行cmd命令的代码片段,但我无法理解它。

以下是用于打开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();
    }
}

我还找到了其他链接,可以添加其他命令,例如cd命令 http://www.coderanch.com/t/109753/Linux-UNIX/exec-command-cd-command-java

如何使用Java打开命令提示符并插入命令?

有人可以帮助我理解如何cd到一个目录吗,例如:

 cd C:\Program Files\Flowella

然后在该目录上运行其他命令?


这里有一些代码 - http://viralpatel.net/blogs/how-to-execute-command-prompt-command-view-output-java/ - Steam
15个回答

161

在Java程序的工作目录不同于另一个目录时,可以通过更改目录并在同一命令行中运行进程来实现。您可以通过让cmd.exe运行类似于cd some_directory && some_program这样的命令行来实现。

以下示例更改到不同的目录并从该目录运行dir。诚然,我可以直接使用dir而无需cd到它,但这只是一个示例:

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);
        }
    }
}

请注意,我正在使用ProcessBuilder来运行命令。其中一项功能是允许我调用redirectErrorStream(true)将进程的标准错误重定向到其标准输出。这样做可以使我只从一个流中读取内容。

在我的机器上,这会给我以下输出:

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

非常感谢... :) 我在cd命令后面加了另一个命令,想要在当前目录下执行它,它使用了一些Android命令,但是它给了我一个错误提示:“android不是内部或外部命令”,尽管它在cmd上可以运行,并且我已经将路径添加到环境变量中。 - Reham
12
@Steam:“cmd.exe”是命令提示符。 “/c”告诉命令提示符运行剩余的命令,然后退出。使用命令提示符可以让我更改目录——“cd”内置于命令提示符中,没有“cd.exe”,还可以使用“&&”连接两个命令。 - Luke Woodward
这对我在Jenkins Groovy控制台脚本方面非常有帮助。非常感谢! - Oseack
@LukeWoodward .. 我们能否在不打开 cmd.exe 的情况下从 shell 脚本运行长时间运行的任务 (git-pull 或 git push),实际上我不想要黑色命令提示屏幕,(我希望它像后台服务一样运行)。 - Tushar Pandey
@LukeWoodward 你好,Luke,请问你能提供在Ubuntu操作系统中执行相同命令的方法吗? - Kumar
显示剩余7条评论

18

您可以尝试这个:

Process p = Runtime.getRuntime().exec(command);

1
也许是因为你正在使用Runtime.getRuntime().exec(...)而不是ProcessBuilder?个人认为Runtime.getRuntime().exec(...)已经过时了。(虽然这不是我踩的) - Luke Woodward
4
我并不是给你点踩的人,但是你的代码与原帖作者已经有的代码几乎完全相同。它无法解决原帖作者当前遇到的问题。 - ruakh

10

如果您想执行像cd这样的操作,请使用:

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

例子:

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

重要的是将命令和所有参数拆分成字符串数组的不同字符串(否则ProcessBuilder API将无法正确提供它们)。


9

以下是命令行执行的更完整实现。

使用方法

executeCommand("ls");

输出:

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

代码

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);
}

4

我的示例(来自实际项目)

文件夹 - 文件。

zipFile,filesString - 字符串;

        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);
            }
        }

3

最简单的方法是使用Runtime.getRuntime.exec()

例如,在Windows上获取默认浏览器的注册表值:

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

如果需要,可以使用Scanner来获取命令的输出。

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

注意:在String中,\是一个转义字符,必须进行转义才能正常工作(因此使用\\)。


然而,没有名为cd的可执行文件,因为它无法在单独的进程中实现。

当前工作目录很重要的一种情况是执行外部进程(使用ProcessBuilderRuntime.exec())。在这些情况下,您可以明确指定新启动的进程要使用的工作目录。

您的命令最简单的方式:

System.setProperty("user.dir", "C:\\Program Files\\Flowella");

我应该在哪里添加这行代码,你是指 Runtime.getRuntime().exec("cd what?"); 你能给我一个cd命令的例子吗? - Reham
编辑了我的回答,希望能够更清晰地表达。 - syb0rg
谢谢,但我遇到了java.io.IOException: Cannot run program "cd": CreateProcess error=2, The system cannot find the file specified的问题。在java.lang.ProcessBuilder.start(Unknown Source)处。 - Reham
@Reham,请查看我的修订答案,了解为什么您无法按照您想要的方式使用特定命令。 - syb0rg
回复:“在Java程序中,您无法更改当前工作目录,也不应该需要这样做”:这是不正确的。请参阅我的答案。 - ruakh

3
尝试这个:

Process runtime = Runtime.getRuntime().exec("cmd /c start notepad++.exe");

2

一旦您获得了对进程的引用,就可以调用其getOutputStream方法来获取命令提示符的标准输入。然后,您可以使用write方法向流发送任何命令,就像处理其他流一样。

请注意,process.getOutputStream()连接到生成的进程的stdin。同样,要获取任何命令的输出,您需要调用getInputStream,然后像处理其他输入流一样进行读取。


2
停止和禁用服务可以通过以下代码完成:
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();
    }                   
}

启用和启动服务可以通过以下代码完成。
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();
    }               
}

可以通过以下代码在任何文件夹中执行命令。

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();
}

1
你不能以这种方式运行cd,因为cd不是一个真正的程序;它是命令行的内置部分,它所做的就是改变命令行的环境。在子进程中运行它没有意义,因为那么你正在更改该子进程的环境 —— 但是该子进程会立即关闭,丢弃其环境。
要在您实际的Java程序中设置当前工作目录,应编写:
System.setProperty("user.dir", "C:\\Program Files\\Flowella");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接