I was writing a small command line application in Haskell and came across an
annoying issue. I wanted to write a command that works similarly to cat
where you can pipe stdin
to the command like this
tail somefile.txt | fooapp
or operate directly on a file like this
fooapp somefile.txt
The issue that cropped up for me was that using getLine
or getContents
blocked while waiting for stdin
. One option of course is to only try to read
from stdin
when no arguments are passed but my preference in that case would
be to print usage instructions.
The solution I used was something like this (the types likely don’t match on this edited version):
import System.IO (hIsTerminalDevice, stdin)
= do
main -- when receiving piped data then hIsTerminalDevice returns False
<- hIsTerminalDevice stdin
s <- if s then return Nothing else
x do contents <- getContents
(return $ Just contents)
<- case x of
a Nothing -> do
<- getArgs
ar return $ maybe Nothing listToMaybe ar
Just t -> return $ Just [t]