J'essaye de diriger la sortie de l'écho dans une commande en utilisant la méthode spawn_command_line_sync
de GLib. Le problème que j'ai rencontré est que l'écho interprète la commande entière comme argument.
Pour mieux expliquer, j'exécute ceci dans mon code:
"some_var's value" | command
Je m'attendrais la variable à envoyer en écho au tube et la commande s'exécute avec les données acheminées, mais quand je vérifie le résultat, cela fait simplement écho à tout après l'écho comme ceci:
string command = "echo \"" + some_var + "\" | command"; Process.spawn_command_line_sync (command.escape (), out r, out e, out s);
Je pense Je pourrais simplement utiliser la classe Posix
pour exécuter la commande, mais j'aime avoir le résultat, l'erreur et les valeurs de statut à écouter que la méthode spawn_command_line_sync
fournit.
3 Réponses :
Le problème est que vous fournissez une syntaxe shell à ce qui est essentiellement l'appel système exec ()
du noyau. L'opérateur de canal shell redirige le stdout d'un processus vers le stdin du suivant. Pour implémenter cela en utilisant Vala, vous devez obtenir le descripteur de fichier pour le stdin du processus command
que vous exécutez, et y écrire some_var
manuellement. P >
Ouais, j'espérais pouvoir éviter d'utiliser spawn_async_with_pipes
ici mais je suppose que je ne peux pas. Je vais mettre à jour cela avec l'implémentation complète dans un peu, merci.
Voici l'implémentation complète et fonctionnelle:
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 */ }
Je suppose que jouer avec FileStream est ce qui a vraiment rendu difficile de comprendre cela. S'est avéré être assez simple.
Vous combinez deux sous-processus en un seul. Au lieu de cela, echo
et command
doivent être traités séparément et avoir un tube installé entre eux. Pour une raison quelconque, de nombreux exemples sur Stack Overflow et d'autres sites utilisent les fonctions Process.spawn_ *
, mais l'utilisation de GSubprocess est une syntaxe plus simple.
Cet exemple redirige la sortie de find. code> pour
trier
, puis imprime la sortie sur la console. L'exemple est un peu plus long car il s'agit d'un exemple pleinement fonctionnel et utilise un GMainContext pour les appels asynchrones. GMainContext est utilisé par GMainLoop, GApplication et 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); }
C'est la fonction splice_subprocesses
qui répond à votre question. Il prend le STDOUT de la première commande comme un InputStream
et le joint avec le OutputStream
(STDIN) pour la deuxième commande.
Le La fonction read_piped_commands
prend la sortie de la fin du tube. Il s'agit d'un InputStream
qui a été enveloppé dans un DataInputStream
pour donner accès à la méthode pratique read_line_async
.
Copie possible de Redirection de la sortie d'une application externe démarrée avec glib a>