Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
    
Is Run["ls >> /tmp/ls.txt"] what you want ? –  b.gatessucks Mar 31 '13 at 22:44
    
@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 –  Szabolcs Mar 31 '13 at 22:47
    
Can't you use a combination of StringJoin to build the command and FileNameJoin for the output ? –  b.gatessucks Mar 31 '13 at 22:53
    
@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. –  Szabolcs Mar 31 '13 at 22:56
    
Not helpful: I did Import["!bla ; echo $?"] and knew that last part was the exit status, but that's very far from cross platform –  ssch Mar 31 '13 at 23:02

1 Answer 1

up vote 8 down vote accepted

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} *)
share|improve this answer
    
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) –  ssch Apr 1 '13 at 0:21
    
@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. –  halirutan Apr 1 '13 at 0:22
    
Agreed, very clear the way it is now! –  ssch Apr 1 '13 at 0:25
    
Thank you, this spares me a lot of trouble and a lot of Java doc reading –  Szabolcs Apr 1 '13 at 0:31
    
@halirutan How would you change the Java code, RunThroughWithExitCode, so it gives the exit stream? –  Liam William Jun 18 '13 at 21:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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