Guillaume Chérel
Guillaume Chérel

Reputation: 1518

How to output to terminal but not pipe (or vice versa)

I'd like to display some text to the terminal but not send this text to a piped process. The purpose is to format differently the data that is being displayed (for pretty printing) and that which is being sent to subsequent processes.

For example, I would like, once the executable is called like this:

$ execname | otherproc

to both output something that will be displayed on the terminal and send some string through the pipe to otherproc. Is there something, maybe like a System.IO.Handle such as stdout, that I could use to send data either to be displayed in terminal or to the pipe?

Upvotes: 1

Views: 213

Answers (2)

Guillaume Chérel
Guillaume Chérel

Reputation: 1518

The following seems to be working: send the data that is meant to be piped to the standard output (with putStrLn for example), and the data to be displayed to the file /dev/tty. For example, the following send "a" to both:

import qualified System.IO as SIO

main = do
    SIO.withFile "/dev/tty" SIO.WriteMode (\h -> SIO.hPutStrLn h "a")
    putStrLn "a"

That way, running the shell command

$ myProg | sed 's/a/A/'

in a terminal displays:

a
A

Only the second A was replaced, i.e. the one send to sed through the pipe with putStrLn, and not the one directly written to /dev/tty.

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476729

Yes, if you make some assumptions. You can check if it is the console by using the System.Console.Terminal.Size module:

import System.Console.Terminal.Size(size)

isConsole :: IO Bool
isConsole = liftM isJust size

basically what happens is it checks if the terminal has defined a size (so it is Just x). If so we assume it is a terminal, if not we make the assumption that it is a pipe (which has no size). Of course it is up to a console to specify its size properly.

Upvotes: 2

Related Questions