Как передать процесс, используя vala / glib - PullRequest
0 голосов
/ 26 января 2019

Я пытаюсь передать вывод из echo в команду, используя метод spawn_command_line_sync GLib. Проблема, с которой я столкнулся, заключается в том, что echo интерпретирует всю команду как аргумент.

Чтобы лучше объяснить, я запускаю это в своем коде:

string command = "echo \"" + some_var + "\" | command";
Process.spawn_command_line_sync (command.escape (), 
                                 out r, out e, out s);

Я ожидал бы, что переменная будет передана в канал, и команда будет запущена с данными, переданными по конвейеру, однако, когда я проверяю результат, он просто выводит все после эха, как это:

"some_var's value" | command

Я думаю, я мог бы просто использовать класс Posix для запуска команды, но мне нравится иметь значения result, error и status для прослушивания, которое обеспечивает метод spawn_command_line_sync.

Ответы [ 3 ]

0 голосов
/ 26 января 2019

Вот полная, работающая реализация:

try {
    string[] command = {"command", "-options", "-etc"};
    string[] env = Environ.get ();
    Pid child_pid;
    string some_string = "This is what gets piped to stdin"

    int stdin;
    int stdout;
    int stderr;

    Process.spawn_async_with_pipes ("/",
        command,
        env,
        SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
        null,
        out child_pid,
        out stdin,
        out stdout,
        out stderr);

    FileStream input = FileStream.fdopen (stdin, "w");
    input.write (some_string.data);

    /* Make sure we close the process using it's pid */
    ChildWatch.add (child_pid, (pid, status) => {
        Process.close_pid (pid);
    });
} catch (SpawnError e) {
    /* Do something w the Error */
}

Я думаю, что игра с FileStream - это то, что действительно усложнило понимание этого.Оказалось, довольно просто.

0 голосов
/ 27 января 2019

Вы объединяете два подпроцесса в один.Вместо этого echo и command должны обрабатываться отдельно, и между ними должна быть установлена ​​труба.По какой-то причине во многих примерах на Stack Overflow и других сайтах используются функции Process.spawn_*, но использование GSubprocess является более простым синтаксисом.

В этом примере выполняется конвейеризация вывода find . в sort, а затем выводится выводна консоль.Пример немного длиннее, потому что это полностью рабочий пример и использует GMainContext для асинхронных вызовов.GMainContext используется GMainLoop, GApplication и GtkApplication:

void main () {
    var mainloop = new MainLoop ();
    SourceFunc quit = ()=> {
        mainloop.quit ();
        return Source.REMOVE;
    };
    read_piped_commands.begin ("find .", "sort", quit);
    mainloop.run ();
}

async void read_piped_commands (string first_command, string second_command, SourceFunc quit) {
    var output = splice_subprocesses (first_command, second_command);
    try {
        string? line = null;
        do {
            line = yield output.read_line_async ();
            print (@"$(line ?? "")\n");
            }
        while (line != null);
    } catch (Error error) {
        print (@"Error: $(error.message)\n");
    }
    quit ();
}

DataInputStream splice_subprocesses (string first_command, string second_command) {
    InputStream end_pipe = null;
    try {
        var first = new Subprocess.newv (first_command.split (" "), STDOUT_PIPE);
        var second = new Subprocess.newv (second_command.split (" "), STDIN_PIPE | STDOUT_PIPE);

        second.get_stdin_pipe ().splice (first.get_stdout_pipe (), CLOSE_TARGET);
        end_pipe = second.get_stdout_pipe ();
    } catch (Error error) {
        print (@"Error: $(error.message)\n");
    }
    return new DataInputStream (end_pipe);
}

Это функция splice_subprocesses, которая отвечает на ваш вопрос.Он берет STDOUT из первой команды как InputStream и склеивает его с OutputStream (STDIN) для второй команды.

Функция read_piped_commands получает выходные данные с конца канала.Это InputStream, который был обернут в DataInputStream для предоставления доступа к удобному методу read_line_async.

0 голосов
/ 26 января 2019

Проблема в том, что вы предоставляете синтаксис оболочки для того, что по сути является системным вызовом exec() ядра.Оператор оболочки канала перенаправляет стандартный вывод одного процесса на стандартный поток следующего.Чтобы реализовать это с помощью Vala, вам нужно получить дескриптор файла для stdin процесса command, который вы запускаете, и записать some_var в него вручную.

...