How can I execute all the possible unix(shell) com

2019-06-05 04:13发布

问题:

I have this .php file sending commands to my android application:

I have tried working with:

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

but the commands echo, pwd and some others are not working.

I get the following exception:

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

As far as I understand this is because there is not any shell environment.

Then I have tried writing in a .sh file the command I want and then execute the command this way:

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

and got solved the problem with pwd, echo and most of the commands.

But later on I realized that I want to keep the state of the commands I execute. For example I want to change directory(cd data) and execute the command mkdir Apoel

And here is when I face my problem. What to do?

I came up with another idea:

Make a shell script (.sh) and each time the user wants to execute a command append the new command in it (and run the hole script(.sh) again). But I think is not a very good way to do it!

Is there any easy way to it? Can my application open a terminal easily?

Here is a code I found for a Terminal Emulator, but it is too complicated!

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

回答1:

An interactive shell is one which remains running, waiting for new commands which it receives from stdin, while producing it's output to stdout and stderr - as a result, it's environment including any changes is retained for the duration of the session. For the shell to be useful to a user, stdin, stoud, stderr need to be connected through to the user - via the console, a serial line, or xterm, etc.

On Android, typically what you do is hook onto the pipes corresponding to stdin, stdout, stderr for the shell process that you've created, and use them to push in commands provided by your java program and accept output for your program to interpret/display.

The idea of creating a script and running it would only work in the case where all the commands are entered before any of them execute.



回答2:

First, some background. On any Posix system, in the shell, there are 2 types of commands:

  1. Internal commands (pwd,cd,echo)
  2. external commands (ls,cp,mv, sometimes echo as well)

All the directory context commands (cd,pwd etc) are commands implemented inside the shell and thus require the shell to remain running, if the changes are to hold (for eg. cd /data/local/tmp).

On the other hand, external commands are standalone and can run indepenedently, but acquire their directory context from their parent process (in most cases, the shell).

Now to solve the problem. Yes, using a script is a good idea, but it is painful to implement, as it requires an overhead of file editing. However, we can use the shell to create a script on the fly and execute it using the -c option. For example:

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

In summery:

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

However, this does not give us the capability to set a directory context, so we need to simulate that. Directory contexts can be added by using the Runtime.exec(String command, String[] envp, File dir) method. With this we have the possibility of maintaining directory context between commands. But how do we actually do that? One solution is to append pwd to the command and take the last line of the output as the new directory context. Thus

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

Finally, the last option is to integrate one of the terminal emulators into you app.

[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