Java exec () не возвращает ожидаемый результат связанных команд каналов - PullRequest
6 голосов
/ 18 января 2010

Я звоню программам командной строки, связанным трубами. Все это работает на Linux наверняка.

Мой метод:

protected String execCommand(String command) throws IOException {
    String line = null;
    if (command.length() > 0) {
        Process child = Runtime.getRuntime().exec(command);
        InputStream lsOut = child.getInputStream();
        InputStreamReader r = new InputStreamReader(lsOut);
        BufferedReader in = new BufferedReader(r);

        String readline = null;
        while ((readline = in.readLine()) != null) {
            line = line + readline;
        }
    }

    return line;
}

Если я звоню какому-нибудь файлу cat | grep asd , я получаю ожидаемый результат. Но не все команды работают правильно. Например с этим:

cat /proc/cpuinfo | wc -l

или это:

cat /proc/cpuinfo | grep "model name" | head -n 1 | awk -F":" '{print substr($2, 2, length($2))}

метод вернет ноль. Я предполагаю, что эта проблема зависит от команд форматирования вывода, таких как head , tail , wc и т.д. выхода?

Ответы [ 6 ]

8 голосов
/ 18 января 2010

Канал (например, перенаправление или >) является функцией оболочки, поэтому исключение непосредственно из Java не будет работать. Вам нужно сделать что-то вроде:

/bin/sh -c "your | piped | commands | here"

, который выполняет процесс оболочки с командной строкой (включая каналы), указанной после -c (в кавычках).

Также обратите внимание, что вы должны использовать stdout и stderr одновременно , в противном случае ваш порожденный процесс будет блокировать ожидание, пока ваш процесс будет использовать выходные данные (или ошибки). Подробнее здесь .

2 голосов
/ 19 января 2010

Все еще не нашел правильного решения для выполнения конвейерных команд с Runtime.exec, но нашел обходной путь. Я просто написал эти сценарии для разделения файлов Bash. Затем Runtime.exec вызывает эти сценарии bash и получает ожидаемый результат.

2 голосов
/ 19 января 2010

Каждый, кто использует Runtime.exec, должен прочитать this .

1 голос
/ 18 января 2010

Может быть неплохо проверить поток ошибок процесса .

0 голосов
/ 24 июля 2014

Возможно, немного поздно, но для тех, кто ищет решение, попробуйте это ...

String[] cmd = {
                        "/bin/sh",
                        "-c",
                        "cat /proc/cpuinfo | wc -l"
                    };

Process process = Runtime.getRuntime().exec(cmd);

Всего наилучшего ..

0 голосов
/ 04 февраля 2010

Быстрая и грязная вещь будет:

command = "/bin/sh -c '" + command.replaceAll("'", "'\''") + "'"

Обычно вам нужно следить за инъекцией оболочки (то есть кто-то вводит "; rm -rf /;" в команду). Но это проблема только в том случае, если часть команды может быть введена из какого-либо другого пользовательского ввода.

Медленным и болезненным подходом было бы сделать Bash самостоятельно на Java. Если вы пойдете по этому пути, вы обнаружите все замечательные вещи, которые Bash дает вам , которые напрямую не доступны из Process.exec (каналы, перенаправление, составные команды, расширение переменных, арифметическая оценка, .. .).

  1. Разобрать команду для | символов. Обязательно следите за || и цитируемыми строками.
  2. Создает новый Process для каждой переданной команды.
  3. Создайте Thread s, которые читают выходные данные одной команды и записывают их во входные данные следующей команды.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...