【问题标题】:How can I execute all the possible unix(shell) commands in android programmatically?如何以编程方式在 android 中执行所有可能的 unix(shell) 命令?
【发布时间】:2012-05-05 08:33:36
【问题描述】:

我有这个 .php 文件向我的 android 应用程序发送命令:

我尝试过使用:

Runtime.getRuntime().exec(commandLine);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

但是命令 echo、pwd 和其他一些命令不起作用。

我得到以下异常:

java.io.IOException: Error running exec(). Command: [pwd] Working Directory: null Environment: null

据我了解,这是因为没有任何 shell 环境。

然后我尝试在 .sh 文件中写入我想要的命令,然后以这种方式执行命令:

Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("sh /runCmds/shTest.sh");
InputStream is = proc.getInputStream();

并通过 pwd、echo 和大多数命令解决了问题。

但后来我意识到我想保留我执行的命令的状态。 比如我想换目录(cd data),执行命令mkdir Apoel

这是我面临问题的时候。怎么办?

我想出了另一个主意:

制作一个 shell 脚本 (.sh),每次用户想要执行命令时,在其中添加新命令(并再次运行漏洞脚本 (.sh))。但我认为这不是一个很好的方法!

有什么简单的方法吗?我的应用程序可以轻松打开终端吗?

这是我为终端模拟器找到的代码,但它太复杂了!

https://github.com/jackpal/Android-Terminal-Emulator

【问题讨论】:

    标签: android shell android-intent android-ndk


    【解决方案1】:

    首先,一些背景。在任何 Posix 系统上,在 shell 中,有两种类型的命令:

    1. 内部命令(pwd、cd、echo)
    2. 外部命令(ls、cp、mv,有时还有 echo)

    所有目录上下文命令(cd、pwd 等)都是在 shell 中实现的命令,因此如果要保留更改,则需要 shell 保持运行(例如,cd /data/local/tmp)。

    另一方面,外部命令是独立的,可以独立运行,但从它们的父进程(大多数情况下,shell)获取它们的目录上下文。

    现在解决问题。是的,使用脚本是个好主意,但实施起来很痛苦,因为它需要文件编辑的开销。但是,我们可以使用 shell 动态创建脚本并使用-c 选项执行它。例如:

    /system/bin/sh -c 'cd /data/local/tmp; touch abc; cp abc def; cd /; rm /data/local/tmp/abc'
    

    夏天:

    String sPrefix="/system/bin/sh -c 'cd someplace;";
    String sInputCmd=getCommand(); // this is simulating your command input
    String sPostfix="'";
    
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(sPrefix+sInputCmd+sPostfix); // sh -c 'cd someplace; echo do something'
    InputStream is = proc.getInputStream();
    

    但是,这并没有给我们设置目录上下文的能力,所以我们需要模拟它。可以使用 Runtime.exec(String command, String[] envp, File dir) 方法添加目录上下文。有了这个,我们就有了维护目录的可能性 命令之间的上下文。但我们实际上如何做到这一点?一种解决方案是将pwd 附加到命令中,并将输出的最后一行作为新的目录上下文。因此

    String sPath = "/"; // start in root directory
    String sPrefix = "/system/bin/sh -c 'cd someplace;";
    String sInputCmd; // this is simulating your command input
    String sPostfix = ";echo;pwd'";
    Runtime rt = Runtime.getRuntime();
    while(!(sInputCmd=getCommand()).equals("")) {
        File dir= new File(sPath);
        Process proc = rt.exec(sPrefix+sInputCmd+sPostfix, NULL, dir);
        InputStream is = proc.getInputStream();
        // Do processing on input.
        sPath= last_line_of_is ;
    }
    

    最后,最后一个选项是将其中一个终端模拟器集成到您的应用程序中。

    [1]http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exec%28java.lang.String,%20java.lang.String%5B%5D,%20java.io.File%29

    【讨论】:

    • 你的意思是 /system/bin/sh -c 'the commands here',而不是 su!最好使用绝对路径。
    • 安德烈亚斯,你说得对,我的意思是 sh,而不是 su。我已经更正了。
    • 好!我试图编辑,但它说:编辑必须至少有 6 个非空格字符。 :p
    • Samveen,我喜欢你的回答,但我不知道是否有办法保持打开会话并通知用户 “您当前位于 /system/bin 文件夹中,请输入下一条命令”。这对我来说是最好的答案!
    • 我已更新答案以更符合您的要求。让我知道这是否足够好。我还把我的一些 cmets 移到了聊天室:chat.stackoverflow.com/rooms/10467/…
    【解决方案2】:

    交互式 shell 保持运行,等待从 stdin 接收到的新命令,同时将其输出到 stdout 和 stderr - 因此,它的环境(包括任何更改)在会话期间保留。为了使 shell 对用户有用,stdin、stoud、stderr 需要通过控制台、串行线或 xterm 等连接到用户。

    在 Android 上,通常您所做的是将与您创建的 shell 进程的 stdin、stdout、stderr 对应的管道挂钩,并使用它们来推送您的 java 程序提供的命令并接受程序的输出解释/展示。

    创建脚本并运行它的想法只适用于所有命令在执行之前输入的情况。

    【讨论】:

    • 如何保持打开的会话?你说:所有的命令都是在执行之前输入的。你能用一个例子来解释一下吗?你的意思是这样的:touch abc; cp abc def; cd /; ?
    • 您可以通过保持相同的 shell 副本运行并通过管道与其交互来保持会话打开。如果您使用脚本的想法,则必须在运行任何命令(并从中获取输出)之前将所有命令放入脚本中(是的,这有点像将它们放在一行中 ; ) - 此时你将不再是互动的。可能是时候再次尝试了解这些终端仿真器源了。
    猜你喜欢
    • 2013-01-26
    • 2013-08-14
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2014-05-17
    • 1970-01-01
    相关资源
    最近更新 更多