18
$\begingroup$

Run["program"] will run an external program and return the return code.

Import["!program", "String"] will run the program and return the output as a string.

How can I get both the output and the return code? I need a cross platform solution.

It would be nice (but not strictly necessary) to get stderr too. Do we need J/Link to achieve this?

$\endgroup$
5
  • $\begingroup$ Is Run["ls >> /tmp/ls.txt"] what you want ? $\endgroup$ Commented Mar 31, 2013 at 22:44
  • $\begingroup$ @b.gatessucks Yes, but that's rather ugly and has its own problems. For example, if I don't want to make a mess, I need to make sure I'm writing into the temp directory; if that has spaces in the path, I need to escape them; and so on $\endgroup$
    – Szabolcs
    Commented Mar 31, 2013 at 22:47
  • $\begingroup$ Can't you use a combination of StringJoin to build the command and FileNameJoin for the output ? $\endgroup$ Commented Mar 31, 2013 at 22:53
  • $\begingroup$ @b.gatessucks Yes, of course it's possible, but it's a lot of trouble. Can you show off hand how to do it in a way which will work on all platforms and there won't be problems with spaces in file names or paths? I think even RunThrough had a bug because it didn't handle spaces properly on Windows XP. $\endgroup$
    – Szabolcs
    Commented Mar 31, 2013 at 22:56
  • $\begingroup$ Not helpful: I did Import["!bla ; echo $?"] and knew that last part was the exit status, but that's very far from cross platform $\endgroup$
    – ssch
    Commented Mar 31, 2013 at 23:02

2 Answers 2

10
$\begingroup$

I would say JLink is one of the fastest ways to do this. Just use the Runtime to start a process executing your command and collect the exit code too:

<< JLink`

RunThroughWithExitCode[cmd_String] :=
 JavaBlock[Module[{ireader, istream, runtime, process, reader},
   LoadJavaClass["java.lang.Runtime"];
   runtime = Runtime`getRuntime[];
   process = runtime@exec[cmd];
   process@waitFor[];
   istream = process@getInputStream[];
   ireader = JavaNew["java.io.InputStreamReader", istream];
   reader = JavaNew["java.io.BufferedReader", ireader];
   {reader@readLine[], process@exitValue[]}
   ]]

And then you get

RunThroughWithExitCode["uname -a"]
(* {Linux lenerd 3.2.0-39-generic #62-Ubuntu SMP 
    Thu Feb 28 00:28:53 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux,
   0}
*)

The same approach can be used to catch the error stream of the process.

When you are on a system with a bash, you could collect everything in the system call itself. This is basically the same idea that was already suggested by @ssch

RunThroughWithExitCode2[cmd_String] :=
 ToExpression@Import[
 "!out=\"$(eval " <> cmd <> ")\";ret=$?;echo \"{\\\"${out}\\\",${ret}}\"", "String"]

This works too and gives a list of output and return value

RunThroughWithExitCode2["which math"]
(* {"/usr/local/Wolfram/Mathematica/9.0.1/Executables/math", 0} *)
$\endgroup$
13
  • $\begingroup$ output = {Rest@NestWhileList[ reader@readLine[] &, "", # =!= Null &, 1, Infinity, -1] , process@exitValue[]} or similar to return all lines of the result (possibly want to StringJoin with "\n" inter-spaced) $\endgroup$
    – ssch
    Commented Apr 1, 2013 at 0:21
  • $\begingroup$ @ssch In the version I tested here, I read all output too, but I wanted the function as small as possible. I think the rest can be adapted easily. $\endgroup$
    – halirutan
    Commented Apr 1, 2013 at 0:22
  • $\begingroup$ Agreed, very clear the way it is now! $\endgroup$
    – ssch
    Commented Apr 1, 2013 at 0:25
  • $\begingroup$ Thank you, this spares me a lot of trouble and a lot of Java doc reading $\endgroup$
    – Szabolcs
    Commented Apr 1, 2013 at 0:31
  • 1
    $\begingroup$ @Liam Because the output is the data you send to the process. This becomes clear when you read here. Unfortunately, I have not much experience with Windows. $\endgroup$
    – halirutan
    Commented Jun 19, 2013 at 7:52
9
$\begingroup$

For those who will encounter the same problem as mine (and OP's), I added this answer.

Mathematica now(since 10.0.0) has a new built-in function called RunProcess which does exactly what OP asked (including the standard error).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.