I have started using Mathematica to automate file backup operations. The logistics I need make Mathematica a good choice. I am testing and developing the Notebook manually, and Print outputs document the operational events. The saved Notebook provides a record of the process for that day.

I would like to have an easy way to direct Print output to a separate file, for example, by adding

DirectPrintOutputTo["filename "<>DateList["Year","Month","Day"]<>".txt"] 

at the beginning of a Notebook. The advantages of this approach seem obvious. I assume I would need to load my function from a package before calling it. Is something like this this possible? Any suggestions about how to do it?

Alternatively, maybe I could write a print function called PrintTo that would, on first use, open an output file with the name assigned to printToFileName, and I could use the editor to change all the Print functions to PrintTo functions. Not so fancy, but I think I know how to how to do it.

I think that I answered my own question, in the sense that my alternative idea seems straightforward and pretty implementable.

  • $\begingroup$ My current scripting approach used Print statements to print results to the scripting notebook. I don't think PutAppend would work (but I may not understand your suggestion). $\endgroup$ Commented Jul 26, 2013 at 19:34
  • $\begingroup$ I have missunderstood the question, I thought you are going to write this not to change Print. So it is not good suggestion then :) $\endgroup$
    – Kuba
    Commented Jul 26, 2013 at 19:54
  • 2
    $\begingroup$ Possible duplicates: (5040), (7081), (22584) $\endgroup$
    – Mr.Wizard
    Commented Jul 26, 2013 at 20:31
  • $\begingroup$ I wonder if one could use 'TagSet' to make extend the functionality of 'Print' to your specific needs. I don't have much time to think through this now (heading away for a week). May I can work something up later tonight. $\endgroup$
    – Jagra
    Commented Jul 27, 2013 at 17:30

3 Answers 3


From the documentation for Print: "Print sends its output to the channel $Output."

Therefore you can just do this:

$Output = OpenWrite["filename " <> DateList["Year", "Month", "Day"] <> ".txt"];

before you run the file.

Something more structured would be like this:

stream = OpenWrite["c:/users/gre/desktop/derp.txt"];
AppendTo[$Output, stream];

(* run your file here *)

$Output = Most[$Output];

Since Print by default outputs to stdout, you could also pipe the output by running the notebook as a script.

  • $\begingroup$ I tried using Block[{$Output = ..., but this didn't seem to work for $Output. $\endgroup$
    – amr
    Commented Jul 26, 2013 at 20:20
  • $\begingroup$ Beat me to the punch about $Output. However, I was working on a generic environment. $\endgroup$
    – rcollyer
    Commented Jul 26, 2013 at 20:21
  • $\begingroup$ @rcollyer Well you both beat me, so... $\endgroup$
    – Mr.Wizard
    Commented Jul 26, 2013 at 20:23
  • $\begingroup$ @rcollyer agreed. usually i go the lazy route :D $\endgroup$
    – amr
    Commented Jul 26, 2013 at 20:23
  • 3
    $\begingroup$ @Mr.Wizard I beat both of you a long time ago, and Leonid. :) $\endgroup$
    – rcollyer
    Commented Jul 26, 2013 at 20:24

I don't recommend modifying Print to redirect the output when it is not necessary. Instead, you can build up a custom solution that suits your needs. I use a variant of the following for logging in my projects and you should be able to tweak them to your application.

Clear[logFile, writeLog, showLog];
logFile := "project-" <> DateString[##, {"Year", "Month", "Day"}] <> ".log" &;

writeLog[message_String] := 
    Module[{str = OpenAppend[logFile[]], date = DateString[]}, 
        WriteString[str, StringJoin @@ Riffle[{date, message, "\n"}, "\t"]];

showLog := FilePrint@logFile@## &;
clearLog := Module[{str = OpenWrite[logFile@##]}, Close@str;] &

Note the use of OpenAppend and OpenWrite in the above functions. OpenAppend creates a new file if none exists, but appends to an already existing file. OpenWrite, on the other hand, simply creates a new empty file regardless of whether a file already exists with that name (thus erasing data, which is what we want here).

Since writeLog just takes a string as input, you can simply replace your Print commands with writeLog and it should work fine.

(* "project-20130726.log" *)

writeLog["Hello world"];
(* Fri 26 Jul 2013 12:51:31 Hello world *)

(* crickets *)

This is already built-in; Print directs all output to the $Output channel where a channel is just a list of open streams. So, to redirect it, simply

oldout = $Output;
    strm = OpenAppend["filename "<>DateString[]<>".txt"];    
    $Output = {strm};

and to switch it back

$Output = oldout;

Assuming you just want an environment where Print is re-directed, you could do something like this

SetAttributes[RedirectPrint, HoldRest];
Options[RedirectPrint] = {OpenMethod -> OpenAppend};
RedirectPrint[filename_String, body_, opts:OptionsPattern[]] :=
 Block[{old, strm, open},
  open = OptionValue[OpenMethod]; (* needs error checking here *)
  old = $Output;
        strm = open[filename];
        $Output = {strm},
    $Output = old;
  • $\begingroup$ @Mike the change is good, I was taking the OP's code directly without looking at it ... $\endgroup$
    – rcollyer
    Commented Jul 28, 2013 at 3:09

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.