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
or operate directly on a file like this
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)
main = do
-- when receiving piped data then hIsTerminalDevice returns False
s <- hIsTerminalDevice stdin
x <- if s then return Nothing else
(do contents <- getContents
return $ Just contents)
a <- case x of
Nothing -> do
ar <- getArgs
return $ maybe Nothing listToMaybe ar
Just t -> return $ Just [t]