Overview
本章主要介紹如何通過(guò)這幾種語(yǔ)言來(lái)執(zhí)行 Shell 命令。
Java
執(zhí)行 Shell 命令
Java 中執(zhí)行 Shell 命令主要依靠 Runtime 和 Process 兩個(gè)類(lèi)。
例:
try {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ls -al ..");
// 等待 Shell 執(zhí)行的結(jié)果,0 為正常執(zhí)行完畢
int exitValue = process.waitFor();
if (exitValue != 0) {
System.out.println("exit with " + exitValue);
return;
}
// 輸出 Shell 執(zhí)行的結(jié)果
try (InputStream in = process.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader reader = new BufferedReader(isr)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
以上例子可以看到在 Java 中執(zhí)行 Shell 命令還是比較復(fù)雜的,簡(jiǎn)單的 ls 也需要不少代碼,不過(guò)其中大部分都是普通的 IO 流操作。
Pipe 操作
Pipe 操作在 Shell 命令中非常常見(jiàn),可惜的是 Java 無(wú)法直接通過(guò)執(zhí)行 Shell 命令來(lái)實(shí)現(xiàn)此功能,而必須使用執(zhí)行腳本的方式才能正常執(zhí)行。
例:
try {
Runtime runtime = Runtime.getRuntime();
String[] cmd = {"/bin/sh", "-c", "ls -al .. | grep JGSK"};
Process process = runtime.exec(cmd);
int exitValue = process.waitFor();
if (exitValue != 0) {
System.out.println("exit with " + exitValue);
return;
}
try (InputStream in = process.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader reader = new BufferedReader(isr)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
相比較直接執(zhí)行命令而言,只是 runtime.exec() 這個(gè)方法的參數(shù)有了變化。
從控制臺(tái)讀取輸入
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
Groovy
執(zhí)行 Shell 命令
Groovy 中對(duì) Java 的方法做了一些包裝,使用起來(lái)更加簡(jiǎn)單。
例:
def p = "ls -al ..".execute()
def exitValue = p.waitFor()
if (exitValue != 0) {
println("exit with $exitValue")
return
}
println "${p.text}"
Pipe 操作
Groovy 也無(wú)法直接在命令中執(zhí)行 Pipe 操作,但是卻提供了 pipe() 方法用以連接兩個(gè) Process。
例:
def p1 = "ls -al ..".execute()
def p2 = "grep JGSK".execute()
def p3 = p1.pipeTo(p2)
exitValue = p3.waitFor()
if (exitValue != 0) {
println("exit with $exitValue")
return
}
println "${p3.text}"
從控制臺(tái)讀取輸入
例:
def scanner = new Scanner(System.in)
println(scanner.nextLine())
Scala
執(zhí)行 Shell 命令
Scala 執(zhí)行 Shell 命令只要使用 ! 方法就可以了。
val exitValue = "ls -al .." !
以上例子會(huì)進(jìn)行阻塞并返回執(zhí)行結(jié)果,0 表示正常執(zhí)行完畢。
val result = "ls -al .." !!
以上例子會(huì)進(jìn)行阻塞并返回執(zhí)行完畢的輸出結(jié)果,如果沒(méi)有正常執(zhí)行完畢則拋出異常。
通過(guò)以上兩個(gè)例子可以看到 Scala 操作 Shell 簡(jiǎn)簡(jiǎn)單單一句話(huà)就可以搞定。
Pipe 操作
Scala 進(jìn)行 Pipe 操作非常接近實(shí)際在 Shell 中執(zhí)行的命令,只是使用 #| 替換了 |。
"ls -al .." #| "grep JGSK" !
實(shí)際上 # 可以與各種操作結(jié)合用在多種地方,比如說(shuō)文件的輸出。
"ls -al .." #> new File("shell.txt") !
"ls -al .." #>> new File("shell.txt") !
從控制臺(tái)讀取輸入
例:
println(StdIn.readLine())
Kotlin
執(zhí)行 Shell 命令
Kotlin 目前沒(méi)有自己的 Api,所以只能調(diào)用 Java 的方法。
例:
val runtime: Runtime = Runtime.getRuntime()
val process: Process = runtime.exec("ls -al ..")
val exitValue = process.waitFor()
if (exitValue != 0) {
println("exit with $exitValue")
return
}
process.inputStream.bufferedReader().lines().forEach {
println(it)
}
從控制臺(tái)讀取輸入
例:
println(readLine())
Summary
- 各種語(yǔ)言都可以進(jìn)行 Shell 操作,但是只有 Scala 和 Groovy 的 api 具有實(shí)際生產(chǎn)力。
文章源碼見(jiàn) https://github.com/SidneyXu/JGSK 倉(cāng)庫(kù)的 _32_shell 小節(jié)