在电脑上可以打开 cmd/powershell/iTerm2/Git Bash 进行命令行的操作,但是如何用其他语言比如 Python/Java 执行命令行呢?
这么做当然不是闲的蛋疼,而是有些工作的确依赖这样的实现。
Java 和 Kotlin 本质上都是运行在 jvm 虚拟机上,都是调用 Runtime 接口提供的方法。以下以 Java为例。
public class CmdShell { public static void main(String[] args) { run(); } private static void run() { String os = System.getProperty("os.name").toLowerCase(); System.out.println(os); if (os.toLowerCase().contains("mac")) { runOnMac("ls"); runOnMac("ls -hl"); runOnMac("adb devices"); } else if (os.contains("windows")) { runOnWindows("dir"); runOnWindows("git log"); } } private static void runOnWindows(String cmd) { Runtime runtime = Runtime.getRuntime(); String realCmd = "cmd /c " + cmd; try { Process p = runtime.exec(realCmd); String result = StreamUtil.StreamToStringWithReader(p.getInputStream()); String output = String.format("execute cmd : %s and result is /n/n%s ", cmd, result); System.out.println(output); } catch (IOException e) { e.printStackTrace(); } } private static void runOnMac(String cmd) { Runtime runtime = Runtime.getRuntime(); try { Process p = runtime.exec(cmd); String result = StreamUtil.StreamToStringWithReader(p.getInputStream()); String output = String.format("execute cmd : /" %s /" and result is /n/n%s ", cmd, result); System.out.println(output); } catch (IOException e) { e.printStackTrace(); } } }
Android 应用层的实现,本质上还是 Java 或 Kotlin,因此代码实现基本和上面:point_up_2:一致。但是本质上执行命令的还是内核,因此需要执行某些命令是需要权限的,具体权限可能和厂商对 ROM 的实现有关。一些比较有用的命令还是可以执行的比如, pwd,ifconfig,ping ,但是 ls 命令是需要权限的(估计 root 之后的手机是可以的,2019 年想 root 一个手机忽然发现已经很难了 :cry:)。借助 ping 命令可以做网络相关的一些事情。
import os def os_open(): """ popen方法通过p.read()获取终端输出,而且popen需要关闭close(). 当执行成功时,close()不返回任何值,失败时,close()返回系统返回值.. 可见它获取返回值的方式和os.system不同 强调的一点是,不支持参数,不支持管道 :return: """ out = os.popen("dir") print(out.read()) out.close()
popen返回的是一个file对象,跟open打开文件一样操作了,r是以读的方式打开. 用 python 执行命令行,最有意思的实现莫过于之前很火爆的微信小程序游戏《跳一跳》的 刷分程序 。就是通过分析图片计算位置,然后在程序内调用 adb shell swipe x,y 命令实现的
这里的 gradle 指工程构建过程的 build.gralde 或 customXXX.gradle 脚本文件。在这些脚本文件中,其实也是可以执行命令行的。
def getGitBranch() { def stdout = new ByteArrayOutputStream() exec { commandLine "git" args "rev-parse", "--abbrev-ref", "HEAD" standardOutput = stdout } return stdout.toString().trim() } ext { getGitBranch = this.&getGitBranch }
这样就可以使用 gitGitBranch 方法获取当前工程的 git 分支了。可以看到 最核心的实现,就是把要执行的命令写到 exec 的闭包当中,然后用一个 OutputStream 的装饰器接收一下输出就可以了 。当然,如果你要执行的命令,不关注结果,输出就可以忽略了。
我们知道 groovy 编译后的字节码也是在 JVM 虚拟机上执行。只是他作为一种动态类型的语言,使用起来比较灵活。在 groovy 中执行命令行和 gradle 非常相似.
class GitTool { static String getGitBranch(Project project) { def out = new ByteArrayOutputStream() project.exec { it.commandLine("git") it.args("rev-parse", "--short", "HEAD") it.standardOutput = out } return out.toString().trim() } }
你可以理解为把闭包的实现给展开了。
关于 JavaScript 这里简单讨论一下之前自己使用 Node 时的场景。浏览器内是如何一番场景,不太了解不做分析。
function run_cmd(cmd, args, callBack ) { var spawn = require('child_process').spawn; var child = spawn(cmd, args); var resp = ""; child.stdout.on('data', function (buffer) { resp += buffer.toString() }); child.stdout.on('end', function() { callBack (resp) }); } run_cmd( "ls", ["-l"], function(text) { console.log (text) });
run_cmd 方法定义了具体实现,后续使用此方法即可。
…… may be continued