如何使用vala / glib传递到进程

时间:2019-01-26 18:45:57

标签: glib vala elementary

我正在尝试使用GLib的spawn_command_line_sync方法将回声的输出传递到命令中。我遇到的问题是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类来运行命令,但是我喜欢使用spawn_command_line_sync方法提供的结果,错误和状态值来监听。

3 个答案:

答案 0 :(得分:4)

您正在将两个子流程组合为一个。相反,echocommand应该分开对待,并在它们之间设置管道。由于某些原因,Stack Overflow和其他站点上的许多示例都使用Process.spawn_*函数,但是使用GSubprocess是更简单的语法。

此示例将find .的输出通过管道传输到sort,然后将输出打印到控制台。该示例稍长一些,因为它是一个完全正常的示例,并且使用GMainContext进行异步调用。 GMainLoop,GApplication和GtkApplication使用GMainContext:

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便捷方法。

答案 1 :(得分:3)

问题是您要为本质上是内核exec()的系统调用提供shell语法。 Shell管道运算符将一个进程的标准输出重定向到下一个进程的标准输入。要使用Vala来实现该功能,您需要获取正在运行的command进程的stdin的文件描述符,并手动将some_var写入其中。

答案 2 :(得分:2)

这是完整的有效实施方式:

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确实很难解决这个问题。原来非常简单。