java调用cmdsh命令
Java调用Windows命令
Java调用CMD命令
Java调用CMD命令,轻松实现系统级操作!
java如何执行bat脚本,并监控执行结果
Java中如何执行多条shell/bat命令
Java 执行Shell脚本指令
java调用shell脚本并传递参数
java调用shell并传参
java执行shell/CMD命令
文章目录
- Java调用CMD命令
- 一、Java调用CMD命令的基本方法
- 二、使用Runtime类调用CMD命令
- 三、使用ProcessBuilder类调用CMD命令
- 四、解决编码问题的注意事项
- 五、Java调用CMD命令的实用技巧
- Java调用CMD命令,轻松实现系统级操作!
- 详解
- 注意事项
- Java调用Windows命令
- [Java ProcessBuilder examples](https://mkyong.com/java/java-processbuilder-examples/)
- 1. Ping
- 2. Ping + Thread
- 3. Change Directory
- Java 执行Shell脚本指令
- 一、介绍
- 二、调用Shell脚本
- 1、获取键盘输入
- 2、构建指令
- 3、java程序
- 三、调试心得
- 1、构建指令不对
- 2、文件格式不对
- 四、参考文献
- 通义灵码
- Process执行命令如何结束
- Process执行命令如何正确关闭
- `cmd /c` 的含义
- 详细解释
- 示例
- 为什么使用 `cmd /c`
- 总结
- `"sh", "-c"` 的含义
- 详细解释
- 示例
- 在 Java 中的使用
- 为什么使用 `"sh", "-c"`
- 示例代码
- 解释
- FFmpegShellUtils
- ShellUtils
Java调用CMD命令
在Java开发中,有时候需要与操作系统的命令行交互,执行特定的CMD命令或脚本。然而,处理编码问题是调用CMD命令时常遇到的挑战。正确处理编码可以避免输出结果的乱码,确保程序的稳定运行。本文将介绍Java中调用CMD命令的方法,并重点解决编码问题,同时提供一些实用技巧和注意事项。
一、Java调用CMD命令的基本方法
Java通过Runtime类或ProcessBuilder类提供了调用CMD命令的能力。这两个类都允许Java程序启动一个新的进程并执行特定的命令,通过标准输入输出流进行数据交换。Runtime类适用于简单的命令执行,ProcessBuilder类则更加灵活,适用于复杂的命令和参数传递。
二、使用Runtime类调用CMD命令
Runtime类提供了exec()方法来执行CMD命令。该方法接收一个String类型的命令字符串,并返回一个Process对象,通过这个对象可以获取命令执行的结果。
示例代码:
import java.io.*;public class CmdExecutionExample {public static void main(String[] args) {try {// 调用CMD命令String command = "ipconfig";Process process = Runtime.getRuntime().exec(command);// 获取命令输出结果InputStream inputStream = process.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBKString line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待命令执行完成process.waitFor();} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
三、使用ProcessBuilder类调用CMD命令
ProcessBuilder类相比Runtime类更加灵活,可以通过链式调用设置命令和参数,同时还可以设置工作目录、环境变量等。
示例代码:
import java.io.*;public class CmdExecutionExample2 {public static void main(String[] args) {try {// 调用CMD命令ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "ipconfig"); // /c参数表示执行后关闭CMD窗口processBuilder.redirectErrorStream(true); // 将错误输出流与标准输出流合并Process process = processBuilder.start();// 获取命令输出结果InputStream inputStream = process.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBKString line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待命令执行完成process.waitFor();} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
四、解决编码问题的注意事项
- 输出编码:在调用CMD命令时,应确保输出流的编码与CMD命令输出的编码一致。例如,如果CMD命令输出使用GBK编码,Java程序应使用相同的编码读取输出流。
- 输入编码:如果Java程序需要传递参数给CMD命令,应该确认参数的编码与CMD命令支持的编码一致,以避免参数乱码。
五、Java调用CMD命令的实用技巧
- 在Windows系统中,CMD命令通常使用GBK编码输出。因此,在调用CMD命令时,常用的编码为GBK。
- 使用ProcessBuilder类时,可以通过redirectErrorStream(true)方法将错误输出流与标准输出流合并,方便获取完整的输出信息。
- 建议使用try-with-resources语句来关闭流资源,确保资源的及时释放。
Java调用CMD命令是实现与操作系统交互的一种重要方式。解决编码问题是调用CMD命令时必须关注的重要问题,通过设置正确的编码,可以避免输出结果的乱码,确保程序的稳定运行。在实际应用中,合理使用Runtime类或ProcessBuilder类,处理编码问题,可以实现更灵活、稳健的CMD命令调用。
Java调用CMD命令,轻松实现系统级操作!
在Java中,你可以使用Runtime.getRuntime().exec()
方法来调用系统命令行(cmd)命令。这个方法允许你执行任何外部程序或命令,并可以获取其输出。
下面是一个示例代码,展示如何在Java中调用cmd命令:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;public class CmdExample {public static void main(String[] args) {try {// 构建命令String command = "cmd /c dir"; // 这里以列出当前目录为例// 执行命令Process process = Runtime.getRuntime().exec(command);// 读取命令的输出BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}// 等待命令执行完成int exitCode = process.waitFor();System.out.println("Exited with code: " + exitCode);} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
详解
-
构建命令:
String command = "cmd /c dir";
:这里我们使用了Windows的cmd
命令行工具,并通过/c
参数告诉它执行完命令后关闭。dir
是列出当前目录下的文件和文件夹的命令。
-
执行命令:
Process process = Runtime.getRuntime().exec(command);
:这行代码通过运行时环境执行指定的命令。返回的Process
对象可以用来控制进程和获取其输出。
-
读取命令的输出:
- 使用
BufferedReader
包装InputStreamReader
来读取进程的标准输出流(即命令的输出)。 - 循环读取每一行直到没有更多输出。
- 使用
-
等待命令执行完成:
int exitCode = process.waitFor();
:这会阻塞当前线程直到外部进程结束,并返回进程的退出值。通常,0表示正常退出,非0值表示有错误发生。
-
异常处理:
- 捕获并处理
IOException
(输入输出异常)和InterruptedException
(中断异常),这些可能在执行命令或等待过程中抛出。
- 捕获并处理
注意事项
- 确保传递给
exec()
方法的命令字符串是正确的,并且考虑到操作系统的差异(例如,上述代码在Windows上运行,而在Linux上可能需要修改命令)。 - 当处理外部进程时,始终考虑安全性,特别是当命令包含来自用户输入的部分时。
- 对于更复杂的交互,可能需要使用
ProcessBuilder
类而不是Runtime.exec()
,因为ProcessBuilder
提供了更多的配置选项和更好的控制。
Java调用Windows命令
Java调用Windows命令 Java调用Windows命令主要用到两个类: java.lang.Runtime
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。应用程序不能创建自己的 Runtime 类实例。 java.lang.Process
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获取相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。 对于带有 Process 对象的 Java 进程,没有必要异步或并发执行由 Process 对象表示的进程。
package test;import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;/*** Java调用Windows命令测试* @author liuyazhuang**/
public class Test {public static void main(String args[]) {testWinCmd();dirOpt();}public static void testWinCmd() {System.out.println("------------------testWinCmd()--------------------");Runtime runtime = Runtime.getRuntime();System.out.println(runtime.totalMemory());System.out.println(runtime.freeMemory());System.out.println(runtime.maxMemory());System.out.println(runtime.availableProcessors()); //处理器数try {//执行一个exe文件runtime.exec("notepad");runtime.exec("C:\\Program Files\\Microsoft Office\\OFFICE11\\winword.exe c:\\test.doc");//执行批处理runtime.exec("c:\\x.bat");//执行系统命令runtime.exec("cmd /c dir ");runtime.exec("cmd /c dir c:\\");// //-------------- 文件操作 --------------runtime.exec("cmd /c copy c:\\x.bat d:\\x.txt"); //copy并改名runtime.exec("cmd /c rename d:\\x.txt x.txt.bak"); //重命名runtime.exec("cmd /c move d:\\x.txt.bak c:\\"); //移动runtime.exec("cmd /c del c:\\x.txt.bak"); //删除//-------------- 目录操作 --------------runtime.exec("cmd /c md c:\\_test"); //删除} catch (IOException e) {e.printStackTrace();}} /*** 执行批处理文件,并获取输出流重新输出到控制台*/public static void dirOpt() {System.out.println("------------------dirOpt()--------------------");Process process;try {//执行命令process = Runtime.getRuntime().exec("c:\\x.bat");//取得命令结果的输出流InputStream fis = process.getInputStream();//用一个读输出流类去读BufferedReader br = new BufferedReader(new InputStreamReader(fis));String line = null;//逐行读取输出到控制台while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}
}
Java ProcessBuilder examples
In Java, we can use ProcessBuilder
to call external commands easily :
ProcessBuilder processBuilder = new ProcessBuilder();// -- Linux --// Run a shell command
processBuilder.command("bash", "-c", "ls /home/mkyong/");// Run a shell script
processBuilder.command("path/to/hello.sh");// -- Windows --// Run a command
processBuilder.command("cmd.exe", "/c", "dir C:\\Users\\mkyong");// Run a bat file
processBuilder.command("C:\\Users\\mkyong\\hello.bat");Process process = processBuilder.start();
1. Ping
1.1 Run an external ping command to ping a website 3 times, and display the output.
package com.mkyong.process;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;public class ProcessBuilderExample1 {public static void main(String[] args) {ProcessBuilder processBuilder = new ProcessBuilder();// Run this on Windows, cmd, /c = terminate after this runprocessBuilder.command("cmd.exe", "/c", "ping -n 3 google.com");try {Process process = processBuilder.start();// blocked :(BufferedReader reader =new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}int exitCode = process.waitFor();System.out.println("\nExited with error code : " + exitCode);} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}
Output
Pinging google.com [172.217.166.142] with 32 bytes of data:
Reply from 172.217.166.142: bytes=32 time=10ms TTL=55
Reply from 172.217.166.142: bytes=32 time=10ms TTL=55
Reply from 172.217.166.142: bytes=32 time=10ms TTL=55Ping statistics for 172.217.166.142:Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:Minimum = 10ms, Maximum = 10ms, Average = 10msExited with error code : 0
2. Ping + Thread
In above example 1.1, the process.getInputStream
is “blocking”, it is better to start a new Thread for the reading process, so that it won’t block other tasks.
package com.mkyong.process;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;public class ProcessBuilderExample2 {public static void main(String[] args) {ExecutorService pool = Executors.newSingleThreadExecutor();ProcessBuilder processBuilder = new ProcessBuilder();// Run this on Windows, cmd, /c = terminate after this runprocessBuilder.command("cmd.exe", "/c", "ping -n 3 google.com");try {Process process = processBuilder.start();System.out.println("process ping...");ProcessReadTask task = new ProcessReadTask(process.getInputStream());Future<list<string>> future = pool.submit(task);// no block, can do other tasks hereSystem.out.println("process task1...");System.out.println("process task2...");List<string> result = future.get(5, TimeUnit.SECONDS);for (String s : result) {System.out.println(s);}} catch (Exception e) {e.printStackTrace();} finally {pool.shutdown();}}private static class ProcessReadTask implements Callable<list<string>> {private InputStream inputStream;public ProcessReadTask(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic List<string> call() {return new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.toList());}}}
Output
process ping...
process task1...
process task2...Pinging google.com [172.217.166.142] with 32 bytes of data:
Reply from 172.217.166.142: bytes=32 time=11ms TTL=55
Reply from 172.217.166.142: bytes=32 time=10ms TTL=55
Reply from 172.217.166.142: bytes=32 time=10ms TTL=55Ping statistics for 172.217.166.142:Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:Minimum = 10ms, Maximum = 11ms, Average = 10ms
3. Change Directory
3.1 Change to directory C:\\users
and run external dir
command to list out all the files.
package com.mkyong.process;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;public class ProcessBuilderExample3 {public static void main(String[] args) {ProcessBuilder processBuilder = new ProcessBuilder();processBuilder.command("cmd.exe", "/c", "dir");processBuilder.directory(new File("C:\\users"));// can also run the java file like this// processBuilder.command("java", "Hello");try {Process process = processBuilder.start();BufferedReader reader =new BufferedReader(new InputStreamReader(process.getInputStream()));String line;while ((line = reader.readLine()) != null) {System.out.println(line);}int exitCode = process.waitFor();System.out.println("\nExited with error code : " + exitCode);} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}
Output
Volume in drive C has no label.Volume Serial Number is CE5B-B4C5Directory of C:\users//...
Java 执行Shell脚本指令
一、介绍
有时候我们在Linux中运行Java程序时,需要调用一些Shell命令和脚本。而Runtime.getRuntime().exec()方法给我们提供了这个功能,而且Runtime.getRuntime()给我们提供了以下几种exec()方法:
Process exec(String command)
在单独的进程中执行指定的字符串命令。 Process exec(String[] cmdarray)
在单独的进程中执行指定命令和变量。 Process exec(String[] cmdarray, String[] envp)
在指定环境的独立进程中执行指定命令和变量。 Process exec(String[] cmdarray, String[] envp, File dir)
在指定环境和工作目录的独立进程中执行指定的命令和变量。 Process exec(String command, String[] envp)
在指定环境的单独进程中执行指定的字符串命令。 Process exec(String command, String[] envp, File dir)
在有指定环境和工作目录的独立进程中执行指定的字符串命令。
其中,其实cmdarray和command差不多,同时如果参数中如果没有envp参数或设为null,表示调用命令将在当前程序执行的环境中执行;如果没有dir参数或设为null,表示调用命令将在当前程序执行的目录中执行,因此调用到其他目录中的文件和脚本最好使用绝对路径。各个参数的含义:
- cmdarray: 包含所调用命令及其参数的数组。
- command: 一条指定的系统命令。
- envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。
- dir: 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null。
细心的读者会发现,为了执行调用操作,JVM会启一个Process,所以我们可以通过调用Process类的以下方法,得知调用操作是否正确执行:
abstract int waitFor()
导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。
二、调用Shell脚本
1、获取键盘输入
BufferedReader reader = null;try{reader \= new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入IP:");String ip \= reader.readLine();
上述指令基本很常见:
1、创建读入器:BufferReader
2、将数据流载入BufferReader,即InputStreamReader
3、将系统输入载入InputStreamReader中
4、然后利用reader获取数据。
2、构建指令
shell运行脚本指令为 sh **.sh args,其实这个格式与java格式相同。
我的脚本为:
#!/bin/sh
#根据进程名杀死进程
echo "This is a $call"
if [ $# -lt 2 ]
thenecho "缺少参数:procedure_name和ip"exit 1
fiecho "Kill the $1 process"
PROCESS=`ps -ef|grep $1|grep $2|grep -v grep|grep -v PPID|awk '{ print $2}'`
for i in $PROCESS
doecho "Kill the $1 process [ $i ]"
done
其实所有准备若当,就是无法读取里面的数据,执行shell指令,原因就是:
注意事项:
1.shell脚本必须有执行权限,比如部署后chmod -R 777 /webapps
2.shell文件,必须是UNIX格式,ANSI编码格式,否则容易出问题(可以用notepad++,编辑->文档格式转换,格式->转为ANSI格式(UNIX格式)
3、java程序
/*** @author :dongbl* @version :* @Description:* @date :9:19 2017/11/14*/
public class TestBash {public static void main(String [] args){BufferedReader reader = null;try{reader = new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入IP:");String ip = reader.readLine();String bashCommand = "sh "+ "/usr/local/java/jdk1.8.0_121/lib/stopffmpeg.sh" + " ffmpeg " + ip;
// String bashCommand = "chmod 777 " + "/usr/local/java/jdk1.8.0_121/lib/stopffmpeg.sh" ;
// String bashCommand = "kill -9" + ip;System.out.println(bashCommand);Runtime runtime = Runtime.getRuntime();Process pro = runtime.exec(bashCommand);int status = pro.waitFor();if (status != 0){System.out.println("Failed to call shell's command ");}BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream()));StringBuffer strbr = new StringBuffer();String line; while ((line = br.readLine())!= null){ strbr.append(line).append("\n");}String result = strbr.toString();System.out.println(result);}catch (IOException ec){ec.printStackTrace();}catch (InterruptedException ex){ex.printStackTrace();}}
}
其中文件路径为绝对路径,这点需要注意。
三、调试心得
在调试shell脚本执行过程中,反了几个错
1、构建指令不对
1、开始指令为:
String bashCommand = "/usr/local/java/jdk1.8.0\_121/lib/stopffmpeg.sh "+ " ffmpeg " + ip;
程序报错,权限不足。
2、此时修改为:
String bashCommand = "chmod 777 "+"/usr/local/java/jdk1.8.0\_121/lib/stopffmpeg.sh "+ " ffmpeg " + ip;
记住一定注意空格(格式)但此时依然无法指定脚本指令。3、在发现格式不对后,修改后,还是不行,此时指令为:
String bashCommand = "sh "+ "/usr/local/java/jdk1.8.0\_121/lib/stopffmpeg.sh" + " ffmpeg " + ip;
2、文件格式不对
这是无法读取内容的关键原因,因为sh文件是在Windows系统下生成的,所以需要将格式修改为linux格式的,即(UNIX格式)
此时网上程序可以了,然后看到指令不同,修改指令即可以了。
最后终于调通了,看来格式经验不足啊
四、参考文献
1、java调用shell脚本并传递参数
2、JAVA调用Shell脚本
转载于:https://www.cnblogs.com/polly333/p/7832540.html
本文转自 https://blog.csdn.net/weixin_30892889/article/details/97217607,如有侵权,请联系删除。
通义灵码
Process执行命令如何结束
在 Java 中使用 Process 执行外部命令时,可以通过以下几种方法来结束进程:
1、调用 Process.destroy() 方法
- 这个方法会强制终止进程。适用于需要立即停止进程的情况。
2、调用 Process.destroyForcibly() 方法:
- 这个方法会尝试更加强制地终止进程。通常在 destroy() 方法无效时使用。
3、等待进程自然结束: 使用 Process.waitFor() 方法等待进程自然结束。
- 这个方法会阻塞当前线程,直到进程结束。
4、读取进程的输出流和错误流:
- 确保进程的输出流和错误流被正确读取,否则进程可能会因为缓冲区满而挂起。
import java.io.BufferedReader;
import java.io.InputStreamReader;public class ProcessExample {public static void main(String[] args) {try {// 创建进程Process process = Runtime.getRuntime().exec("your-command-here");// 读取进程的输出流和错误流StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT");StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");outputGobbler.start();errorGobbler.start();// 等待进程结束int exitCode = process.waitFor();System.out.println("Process exited with code: " + exitCode);// 如果需要强制终止进程// process.destroy();// process.destroyForcibly();} catch (Exception e) {e.printStackTrace();}}
}class StreamGobbler extends Thread {private InputStream inputStream;private String type;public StreamGobbler(InputStream inputStream, String type) {this.inputStream = inputStream;this.type = type;}@Overridepublic void run() {try {BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {System.out.println(type + ": " + line);}} catch (IOException e) {e.printStackTrace();}}
}
Process执行命令如何正确关闭
在 Java 中使用 Process 执行外部命令时,正确关闭进程非常重要,以确保资源被释放并且不会留下僵尸进程。以下是一些最佳实践和步骤,确保 Process 被正确关闭:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;public class ShellUtils {public static void executeCommand(String command) {Process process = null;try {// 创建进程process = Runtime.getRuntime().exec(command);// 读取进程的输出流和错误流StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT");StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");outputGobbler.start();errorGobbler.start();// 等待进程结束int exitCode = process.waitFor();System.out.println("Process exited with code: " + exitCode);} catch (Exception e) {e.printStackTrace();} finally {// 尝试终止进程if (process != null) {if (process.isAlive()) {process.destroy();if (process.isAlive()) {process.destroyForcibly();}}// 如果仍然无法终止,使用操作系统的命令if (process.isAlive()) {terminateProcessGroup(process);}}}}private static void terminateProcessGroup(Process process) {try {// 获取进程的 PIDString pid = getProcessId(process);if (pid != null) {// 终止进程组String osName = System.getProperty("os.name").toLowerCase();if (osName.contains("windows")) {// Windows 系统Runtime.getRuntime().exec("taskkill /F /T /PID " + pid);} else {// Unix 系统Runtime.getRuntime().exec("kill -9 -" + pid);}}} catch (IOException e) {e.printStackTrace();}}private static String getProcessId(Process process) {try {Field field = process.getClass().getDeclaredField("pid");field.setAccessible(true);return field.get(process).toString();} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}return null;}
}class StreamGobbler extends Thread {private InputStream inputStream;private String type;public StreamGobbler(InputStream inputStream, String type) {this.inputStream = inputStream;this.type = type;}@Overridepublic void run() {try {BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {System.out.println(type + ": " + line);}} catch (IOException e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}
cmd /c
的含义
cmd /c
是 Windows 命令行中的一个选项,用于执行指定的命令并立即返回控制权。具体来说:
cmd
:启动 Windows 命令解释器(命令提示符)。/c
:表示执行指定的命令后立即退出命令提示符。
详细解释
-
cmd
:- 启动 Windows 命令提示符(Command Prompt)。
- 这是一个命令行解释器,用于执行各种命令和脚本。
-
/c
:- 指定命令提示符在执行完指定的命令后立即退出。
- 语法格式为
cmd /c <command>
,其中<command>
是你希望执行的具体命令。
示例
假设你有一个命令 dir
,用于列出当前目录下的文件和文件夹。你可以使用 cmd /c dir
来执行这个命令:
cmd /c dir
这条命令会启动命令提示符,执行 dir
命令,然后立即退出命令提示符。
为什么使用 cmd /c
-
命令组合:
- 有时需要组合多个命令或使用命令行的特殊功能(如管道、重定向等),
cmd /c
可以帮助实现这一点。
- 有时需要组合多个命令或使用命令行的特殊功能(如管道、重定向等),
-
兼容性:
- 在某些情况下,直接执行某些命令可能会遇到路径或环境变量的问题,使用
cmd /c
可以确保命令在正确的环境中执行。
- 在某些情况下,直接执行某些命令可能会遇到路径或环境变量的问题,使用
-
立即退出:
- 使用
/c
选项可以确保命令执行完毕后立即退出命令提示符,不会阻塞当前的 Java 进程。
- 使用
总结
cmd /c
是一个非常有用的命令行选项,特别是在需要执行复杂命令或组合命令时。在你的代码中,它确保 ffmpeg
命令在一个独立的命令提示符窗口中运行,并且在命令执行完毕后立即退出,不会阻塞当前的 Java 进程。
"sh", "-c"
的含义
"sh", "-c"
是在 Unix/Linux 系统中用于启动 shell 并执行指定命令的参数。具体来说:
sh
:启动 Bourne shell(或兼容的 shell,如 Bash)。-c
:表示执行指定的命令字符串,然后退出 shell。
详细解释
-
sh
:sh
是 Unix/Linux 系统中的一个命令行解释器,通常指的是 Bourne shell(Bourne shell 的文件通常是/bin/sh
)。- 它可以执行脚本文件或命令行中的命令。
-
-c
:-c
是sh
的一个选项,表示从命令行参数中读取命令字符串并执行。- 语法格式为
sh -c <command>
,其中<command>
是你希望执行的具体命令。
示例
假设你有一个命令 ls
,用于列出当前目录下的文件和文件夹。你可以使用 sh -c ls
来执行这个命令:
sh -c "ls"
这条命令会启动一个 shell,执行 ls
命令,然后退出 shell。
在 Java 中的使用
在你的代码中,"sh", "-c"
用于启动 shell 并执行指定的命令。这样可以确保命令在 shell 环境中正确解析和执行,特别是当命令包含特殊字符或需要环境变量时。
String[] commandList = new String[]{"sh", "-c", "your-command-here"};
为什么使用 "sh", "-c"
-
命令组合:
- 有时需要组合多个命令或使用 shell 的特殊功能(如管道、重定向等),
sh -c
可以帮助实现这一点。
- 有时需要组合多个命令或使用 shell 的特殊功能(如管道、重定向等),
-
环境变量:
- 使用
sh -c
可以确保命令在正确的 shell 环境中执行,包括环境变量的设置。
- 使用
-
立即退出:
- 使用
-c
选项可以确保命令执行完毕后立即退出 shell,不会阻塞当前的 Java 进程。
- 使用
示例代码
以下是一个示例,展示了如何在 Java 中使用 "sh", "-c"
来执行命令:
import java.io.BufferedReader;
import java.io.InputStreamReader;public class CmdExecutionExample2 {public static void main(String[] args) {String[] commandList = new String[]{"sh", "-c", "ls"};try {Process process = new ProcessBuilder(commandList).start();// 读取进程的输出流和错误流StreamGobbler stdout = new StreamGobbler(process.getInputStream(), "stdout");StreamGobbler errout = new StreamGobbler(process.getErrorStream(), "errout");stdout.start();errout.start();// 等待进程结束int exitCode = process.waitFor();System.out.println("退出码: " + exitCode);} catch (Exception e) {e.printStackTrace();}}static class StreamGobbler extends Thread {private InputStream inputStream;private String type;public StreamGobbler(InputStream inputStream, String type) {this.inputStream = inputStream;this.type = type;}@Overridepublic void run() {try {BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {System.out.println(type + ": " + line);}} catch (IOException e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
}
解释
-
创建进程:
使用ProcessBuilder
创建一个进程,命令列表为{"sh", "-c", "ls"}
。 -
读取输出流和错误流:
使用StreamGobbler
类分别读取进程的输出流和错误流,确保缓冲区不会满。 -
等待进程结束:
使用process.waitFor()
等待进程自然结束,并获取退出码。
通过这些步骤,可以确保命令在 shell 环境中正确执行,并且进程的输出和错误流被正确读取。
FFmpegShellUtils
public class FFmpegShellUtils {// 测试时可以配合命令: tasklist|findstr "ffmpeg", taskkill /f /pid <ffmpeg进程id> , obs拉流 一起观察这个现象public static void main(String[] args) {// 报错: Cannot run program "...": CreateProcess error=2, 系统找不到指定的文件// String[] commandList = new String[]{"ffmpeg -f gdigrab -i desktop -vcodec libx264 -f flv rtmp://192.168.134.3:8002/flv/test"};// 这样写15s后无法结束ffmpeg进程// String[] commandList = new String[]{"cmd", "/c" , "ffmpeg -f gdigrab -i desktop -vcodec libx264 -f flv rtmp://192.168.134.3:8002/flv/test"};// 这样写15s后无法结束ffmpeg进程// String[] commandList = new String[]{"cmd", "/c" , "ffmpeg", "-f", "gdigrab", "-i", "desktop", "-vcodec", "libx264", "-f", "flv", "rtmp://192.168.134.3:8002/flv/test"};// 这样写只是输出了ffmpeg的版本号// String[] commandList = new String[]{"ffmpeg", " -f gdigrab -i desktop -vcodec libx264 -f flv rtmp://192.168.134.3:8002/flv/test"};// 这样可以正常启动ffmpeg, 并在15s后关闭退出String[] commandList = new String[]{"ffmpeg", "-f", "gdigrab", "-i", "desktop", "-vcodec", "libx264", "-f", "flv", "rtmp://192.168.134.3:8002/flv/test"};ProcessBuilder processBuilder = new ProcessBuilder(commandList);try {Process process = processBuilder.start();// 需要命令的输出内容读取出来, 否则进程可能会因为缓冲区满而挂起StreamGobbler stdout = new StreamGobbler(process.getInputStream(), "stdout");StreamGobbler errout = new StreamGobbler(process.getErrorStream(), "errout");stdout.start();errout.start();/*new Thread(() -> {try {System.out.println("开始sleeping");TimeUnit.SECONDS.sleep(15);System.out.println("结束sleeping");System.out.println("开始关闭" + process.isAlive());process.getOutputStream().close();process.destroy();// process.destroyForcibly();System.out.println("关闭成功" + process.isAlive());} catch (InterruptedException | IOException e) {e.printStackTrace();}}).start();*/// 可以在此处等待process结束, 但是需要先开启上面这个线程来结束process, 就可以结束ffmpeg/*int exitCode = process.waitFor();System.out.println("退出码: "+ exitCode);*/System.out.println("开始sleeping");TimeUnit.SECONDS.sleep(15);System.out.println("结束sleeping");System.out.println("开始关闭" + process.isAlive());process.getOutputStream().close();process.destroy();// process.destroyForcibly();System.out.println("关闭成功" + process.isAlive());process = null;LockSupport.park();} catch (IOException | InterruptedException e) {e.printStackTrace();}}}
ShellUtils
public class ShellUtils {public static void main(String[] args) {//=====windows=====// 输出ip地址// ShellUtils.exec("ipconfig");// 弹出记事本, 关闭弹出的记事本, 这个命令才会结束// ShellUtils.exec("notepad");// 弹出记事本, 关闭弹出的记事本, 这个命令才会结束// ShellUtils.exec("cmd", "/c", "notepad");// Cannot run program "dir": CreateProcess error=2, 系统找不到指定的文件// ShellUtils.exec("dir");// 输出目录// ShellUtils.exec("cmd", "/c", "dir");// 输出ip地址// ShellUtils.exec("cmd", "/c", "ipconfig");// ShellUtils.exec("cmd", "/c", "ping www.baidu.com");// 运行ffmpeg// ShellUtils.exec("ffmpeg", "-f", "gdigrab", "-i", "desktop", "-vcodec", "libx264", "-f", "flv", "rtmp://192.168.134.3:8002/flv/test");// =====linux=====// 可以通过ProcessBuilder设置工作目录ShellUtils.exec("sh", "-c", "ls");}public static String exec(String... commandList) {ProcessBuilder processBuilder = new ProcessBuilder(commandList);try {System.out.println("准备执行命令: " + String.join(" ", commandList));// 创建进程Process process = processBuilder.start();// 读取进程的输出流和错误流StreamGobbler stdout = new StreamGobbler(process.getInputStream(), "stdout");StreamGobbler errout = new StreamGobbler(process.getErrorStream(), "errout");System.out.println("准备输出");stdout.start();errout.start();System.out.println("开始等待结果");// 等待进程结束int exitCode = process.waitFor();System.out.println("执行结果:" + exitCode);// 关闭输入流process.getOutputStream().close();stdout.join();errout.join();System.out.println("输出完毕");if (exitCode == 0) {System.out.println("执行成功");return stdout.output.toString();} else {System.out.println("执行失败");return errout.output.toString();}} catch (IOException | InterruptedException e) {e.printStackTrace();throw new RuntimeException("运行发生错误");}}}
public class StreamGobbler extends Thread {// 获取是否为windows系统private static boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");private InputStream inputStream;private String type;StringBuilder output = new StringBuilder();public StreamGobbler(InputStream inputStream, String type) {this.inputStream = inputStream;this.type = type;}@Overridepublic void run() {try {System.out.println(Thread.currentThread().getName() + "-进入输出, type=" + type);String charset = isWindows ? "GBK" : "UTF-8";BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset));String line = null;while ((line = br.readLine()) != null) {System.out.println(Thread.currentThread().getName() + "-线程输出, type=" + type + ", line=>" + line);output.append(line);output.append(System.lineSeparator());TimeUnit.MILLISECONDS.sleep(100);}System.out.println(Thread.currentThread().getName() + "-线程输出结束, type=" + type);} catch (IOException | InterruptedException e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {System.out.println(Thread.currentThread().getName() + "-关闭流发生错误, type=" + type);e.printStackTrace();}}}
}