Reputation: 1518
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
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
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