我正在尝试使用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
方法提供的结果,错误和状态值来监听。
答案 0 :(得分:4)
您正在将两个子流程组合为一个。相反,echo
和command
应该分开对待,并在它们之间设置管道。由于某些原因,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确实很难解决这个问题。原来非常简单。