26
$\begingroup$

I'm playing around with some code that's calling external command-line commands on a windows platform, and when doing this, the command prompt will pop up quickly and then disappear. This is not a huge bother, if you are calling something once, however if you have a loop running and each call takes some time, it becomes a major annoyance. Consider the following code:

 Table[Pause[1/2]; Run[ "dir" ];, {3}];

Is there any way to avoid this behavior, or calling an external program though other methods then by Run[].

$\endgroup$

3 Answers 3

23
$\begingroup$

On Windows 7 using ReadList instead of Run suppresses the window:

Table[Pause[1/2]; ReadList["!dir", String], {3}];

This use of "!command" in place of a file is at least partially documented under OpenRead:

On systems that support pipes,OpenRead["!command"] runs the external program specified by command, and opens a pipe to get input from it.

As Albert Retey notes in the comments, running a command without returning output would therefore best be done with:

Close @ OpenRead @ "!command"

And stated in Joel Klein's answer streams should always be closed. ReadList does this automatically; when using OpenRead we must manually Close the stream.

$\endgroup$
9
  • $\begingroup$ The example was simply an illustration of the behavior of the problem. I'm not actually interested in the output of dir. $\endgroup$
    – jVincent
    Commented Jun 16, 2012 at 1:54
  • 1
    $\begingroup$ @jVincent I'm glad it's working for you. Regarding documentation I've been asked before and I still do not have a good answer. I'm also not sure where "!command" can be used; I've only used Read and ReadList with it myself. $\endgroup$
    – Mr.Wizard
    Commented Jun 16, 2012 at 2:05
  • 1
    $\begingroup$ OpenRead (and OpenWrite) both do support !command. Thus there is a good chance that functions which read or write files will understand that way to open a pipe for reading or writing as they most probably will use these functions (or lower level equivalents). I know that Import also supports it (surprise: that's even documented :-). The limitiation "on symstems that support pipes" seems somewhat outdated, AFAIK all systems where newer versions of Mathematica do run on support pipes. $\endgroup$ Commented Jun 16, 2012 at 9:41
  • 1
    $\begingroup$ @Mr.Wizard: just another note: As OpenRead also supports !command, if you don't need the output Close[OpenRead["!command"]]; could even be more efficient... $\endgroup$ Commented Jun 18, 2012 at 8:53
  • 1
    $\begingroup$ According to documentation, if the file is already open, ReadList will not close it at the end. $\endgroup$
    – user688486
    Commented Dec 30, 2023 at 9:18
21
$\begingroup$

You can call an external (shell) command cmd without showing a command window by using the pipe syntax "!"<>cmd. This can be used in place of a filename with any Mathematica function that opens a file for reading. For example:

  • Import["!dir", "Text"]
  • Read["!dir"] (opens stream, must be closed)
  • OpenRead["!dir"], followed by Read, ReadList etc to grab the command output (opens stream, must be closed).
  • ReadList["!dir"]
  • BinaryReadList["!dir"]
  • Find["!dir", "tmp.txt"] will return the first lines of cmd output containing "tmp.txt"

These functions can be found in guide/LowLevelFileOperations in the Documentation Center.

The general rules used for resolving file names are documented in the Files and Streams tutorial. This is something that has had improvements for Version 9, e.g. URLs can now appear where filenames can go and the resource will be opened by making an HTTP request.

However, be alert that OpenRead["!cmd"] and Read["!cmd"] leave an open InputStream object, that in some cases (depending on the cmd) must be closed before a new, similar command can be run. Closing what has been opened by Read["!dir"] is not trivial, as Read does not return the InputStream object it opens, so one has to check Streams[]. In some cases (again, depending on cmd), an InputStream["!cmd"] object might not be closable (Mathematica hangs) as the running process must be killed via taskkill, the Task Manager or similar. Furthermore, commands that start permanent processes (unlike dir that is terminated immediately) can cause Mathematica to wait until the process is closed outside of Mathematica, e.g.:

ReadList["!notepad.exe"]
Print["next"]

the Print statement is not evaluated and Mathematica does not continue until the appearing Notepad window is closed. On the other hand

stream = OpenRead["!notepad.exe"]
Print["next"]

the Print is evaluated right after the first line and we get back the cursor. The stream of course could only be closed if the Notepad window is closed, so the next example causes Mathematica to wait, and only the first Print is printed before closing Notepad:

stream = OpenRead["!notepad.exe"]
Print["next"]
Close@stream
Print["more"]
$\endgroup$
1
  • $\begingroup$ It doesn't appear something like the following would work ReadList["!cmd /k \"node -p \"console.log('test');\"", String] or with Cygwin ReadList["!\"C:\\cygwin64\\bin\\bash.exe\" -c \"echo test\"", String]. Are you aware of the reason why? $\endgroup$
    – William
    Commented Oct 15, 2015 at 3:23
6
$\begingroup$
Table[Pause[1/2]; Import["!dir","Text"];, {3}];

Import can also be used to pipe command line output straight into Mathematica.

<<"!dir"

Also works.

$\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.