J'essaie de capturer la sortie d'une commande en utilisant Posix.Process.execp
. J'ai porté un code C que j'ai trouvé sur stackoverflow et je peux capturer la sortie pour une exécution, mais je ne peux pas obtenir la sortie pour une seconde exécution.Capture de la sortie standard d'une commande dans SML
Voilà ma fonction:
(* Runs a command c (command and argument list) using Posix.Process.execp. *)
(* If we successfully run the program, we return the lines output to stdout *)
(* in a list, along with SOME of the exit code. *)
(* If we fail to run the program, we return the error message in the list *)
(* and NONE. *)
fun execpOutput (c : string * string list) : (string list * Posix.Process.exit_status option) =
let fun readAll() = case TextIO.inputLine TextIO.stdIn
of SOME s => s :: (readAll())
| NONE => []
(* Create a new pipe *)
val { infd = infd, outfd = outfd } = Posix.IO.pipe()
in case Posix.Process.fork()
of NONE => (
(* We are the child. First copy outfd to stdout; they will *)
(* point to the same file descriptor and can be used interchangeably. *)
(* See dup(2) for details. Then close infd: we don't need it and don't *)
(* want to block because we have open file descriptors laying around *)
(* when we want to exit. *)
(Posix.IO.dup2 { old = outfd, new = Posix.FileSys.stdout }
; Posix.IO.close infd
; Posix.Process.execp c)
handle OS.SysErr (err, _) => ([err], NONE))
| SOME pid =>
(* We are the parent. This time, copy infd to stdin, and get rid of the *)
(* outfd we don't need. *)
let val _ = (Posix.IO.dup2 { old = infd, new = Posix.FileSys.stdin }
; Posix.IO.close outfd)
val (_, status) = Posix.Process.waitpid (Posix.Process.W_CHILD pid, [])
in (readAll(), SOME status) end
end
val lsls = (#1 (execpOutput ("ls", ["ls"]))) @ (#1 (execpOutput ("ls", ["ls"])))
val _ = app print lsls
et est ici la sortie correspondante:
[email protected]:/tmp/test$ ls
a b c
[email protected]:/tmp/test$ echo 'use "/tmp/mwe.sml";' | sml
Standard ML of New Jersey v110.79 [built: Tue Aug 8 16:57:33 2017]
- [opening /tmp/mwe.sml]
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
a
b
c
val execpOutput = fn
: string * string list -> string list * ?.POSIX_Process.exit_status option
val lsls = ["a\n","b\n","c\n"] : string list
val it =() : unit
-
Toutes les suggestions sur ce que je fais mal?
Merci Simon! Je l'ai couru à travers strace et a constaté que bien que le deuxième enfant écrivait à un descripteur de fichier N et stdin du parent a été mis à N par DUP2, le parent n'a jamais lu les messages la deuxième fois. Je posterai une analyse plus détaillée et comment je l'ai réparé demain. –