Clojure: redirecting output to a file

In a scripting language, you often run scripts from a command line and print things to STDOUT. For long output you can redirect it to a file via shell-redirection ($ foo.rb > foo.txt).

But if you're using Clojure for ad-hoc scripting, you're probably sitting in a REPL, not running from a command line. REPLs generally don't have shell-redirection. Printed output just gets dumped into your REPL. This can be annoying. (After a good 10,000 lines of output into a REPL buffer, Emacs starts to lag.)

But you can write a macro to handle this easily enough.

(use 'clojure.contrib.duck-streams)
(defmacro redir [filename & body]
  `(spit ~filename (with-out-str ~@body)))

Then:

user> (redir "foo.txt" (foo) (bar) (baz))

Now whatever (foo) and friends would've printed to STDOUT will instead go to foo.txt. I've found this somewhat useful at work lately.

Edit: better version via Graham Fawcett:

(defmacro redir [filename & body]
  `(binding [*out* (writer ~filename)] ~@body))

5 Comments

http://gravatar.com/avatar/29f838796175982a838a639f984f4e8e.jpg?d=identicon
Dan Ballard says:

Ha, neat trick. Thanks. I'm sure this will work well enough in any Lisp dialect language :)

Nov 12, 2009 10:30 PM PST
http://gravatar.com/avatar/4d84ec3981443dfd9c287e845b60d2ce.jpg?d=identicon
Brian says:

Yeah I'm pretty sure Common Lisp can do it. Any language that lets you dynamically bind the STDOUT handle to some sort of string-writer will do it. You could probably even do it in Ruby with blocks.

Nov 12, 2009 10:41 PM PST
http://gravatar.com/avatar/4243e2efd77a38c8b291f6726212e308.jpg?d=identicon
Graham Fawcett says:

Correct me if I'm wrong, but doesn't your example buffer all of the output of the body (into a string), and then push the string out to a file?

Why not just dynamically bind *out* to the opened file?

Nov 13, 2009 12:57 PM PST
http://gravatar.com/avatar/4d84ec3981443dfd9c287e845b60d2ce.jpg?d=identicon
Brian says:

Right, good point.

Nov 13, 2009 01:22 PM PST
http://gravatar.com/avatar/e5edf448cb9e39e33ea6279ac4403ff8.jpg?d=identicon
Tom Crayford says:
(doc with-out-str)
-------------------------
clojure.core/with-out-str
([& body])
Macro
  Evaluates exprs in a context in which *out* is bound to a fresh
  StringWriter.  Returns the string created by any nested printing
  calls.
nil
Jan 02, 2010 09:40 AM PST

Speak Your Mind

This says COWS.

Preview

Commenting Help

Email / Avatar

  • Supply your email address and your Gravatar will be used.
  • I will never email you and your address won't be published.

No HTML allowed!

All HTML is auto-escaped. Use Markdown. Examples:

  • *emphasis* = emphasis
  • **strong** = strong
  • [link](http://foo.bar) = <a href="http://foo.bar">link</a>
  • `code in backticks` = code in backticks
  •     code indented 4 spaces =
    code indented four spaces
  • > Angle-brace quoted text =
    Angle-brace quoted text