У меня есть этот файл.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
Насколько я понимаю, это потому, что нет оболочки оболочки.
Затем я попытался записать в файл.sh команду, которую я хочу, а затем выполнить команду следующим образом:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("sh /runCmds/shTest.sh");
InputStream is = proc.getInputStream();
и решена проблема с pwd, echo и большинством команд.
Но позже я понял, что хочу сохранить состояние команд, которые я выполняю. Например, я хочу изменить каталог (cd data
) и выполнить команду mkdir Apoel
И вот когда я сталкиваюсь с моей проблемой. Что делать?
Я придумал еще одну идею:
Создайте сценарий оболочки (.sh) и каждый раз, когда пользователь хочет выполнить команду, добавьте в него новую команду (и снова запустите скрипт дыр (.sh)). Но я думаю, что это не очень хороший способ сделать это!
Есть ли простой способ? Могу ли мое приложение легко открыть терминал?
Вот код, который я нашел для эмулятора терминала, но он слишком сложный!
Интерактивная оболочка остается той, которая остается запущенной, ожидая новых команд, которые она получает от stdin, при этом она выводит на stdout и stderr - в результате среда, включая любые изменения, сохраняется на время сеанса. Чтобы оболочка была полезной для пользователя, stdin, stoud, stderr необходимо подключить к пользователю - через консоль, последовательную линию или xterm и т.д.
На Android обычно используется то, что вы делаете, подключаетесь к трубам, соответствующим stdin, stdout, stderr для созданного вами процесса оболочки, и используйте их для ввода команд, предоставляемых вашей java-программой, и принимайте вывод для вашей программы для интерпретации/дисплей.
Идея создания сценария и его запуска будет работать только в том случае, когда все команды вводятся до того, как они выполняются.
Во-первых, некоторый фон. В любой системе Posix в оболочке есть 2 типа команд:
Все команды контекста каталога (cd, pwd и т.д.) Являются командами, реализованными внутри оболочки и, следовательно, требуют, чтобы оболочка оставалась запущенной, если изменения должны удерживаться (например, cd/data/local/tmp
).
С другой стороны, внешние команды автономны и могут выполняться автономно, но приобретают свой контекст каталога из своего родительского процесса (в большинстве случаев - оболочки).
Теперь решить проблему. Да, использование сценария - хорошая идея, но это очень сложно реализовать, так как для этого требуется накладные расходы на редактирование файлов. Однако мы можем использовать оболочку для создания сценария "на лету" и выполнить его с помощью опции -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, 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 ;
}
Наконец, последним вариантом является интеграция одного из эмуляторов терминала в ваше приложение.
touch abc; cp abc def; cd /;
?