packages feed

hscrtmpl-1.2: hscrtmpl.hs

#! /usr/bin/env runhaskell

{- This is a 'skeleton file' for writing shell scripts with Haskell

   Haskell is my go-to language for anything more complicated than a
   simple sequence of shell commands in a bash script. Doing list
   processing and a lot of logic in bash is a grind, to me.

   The idea here is to take a copy of this script and hack it to do
   what you need quickly. Throw the rest out.

   The script starts off (after the imports) with some simple examples
   in main.

   After that are a few functions that simplify things like getting
   the date as a String, logging a date-stamped String to stdout and
   manupulating an ExitCode as a true/false value.

   Finally, there is a comment block full of examples in bash and some
   Haskell code to do something along the same lines.

   Dino Morelli <dino@ui3.info>
   http://ui3.info/d/proj/hscrtmpl.html
   version: 1.2
-}

--import Control.Monad ( when, unless )
import Data.Time
import System.Cmd
import System.Directory
--import System.Environment
import System.Exit
import System.Locale
--import System.Process
import Text.Printf
--import Text.Regex


main :: IO ()
main = do
   printf "This is a shell script\n"

   putStrLn =<< date

   home <- getHomeDirectory
   let prompt = printf "HOME is %s" home
   putStrLn prompt

   logM "Example of a log message"


{- Get the current date/time as a string in RFC822 format
   Looks like this in my locale: Mon Feb 13 16:21:38 EST 2012
-}
date :: IO String
date = dateFormat "%c"


{- Get the current date/time as a string in the specified format
   For format string help, see man 3 strftime
-}
dateFormat :: String -> IO String
dateFormat fmt = formatTime defaultTimeLocale fmt `fmap`
   (getCurrentTime >>= utcToLocalZonedTime)


{- Output a message with datestamp
-}
logM :: String -> IO ()
logM msg = do
   tstamp <- dateFormat "%F %T"
   printf "%s> %s\n" tstamp msg


{- Turn an exit code (say, from system) into a Bool
-}
ok :: ExitCode -> Bool
ok ExitSuccess = True
ok _           = False


{- Turn a Bool into an exit code
-}
toExitCode :: Bool -> ExitCode
toExitCode True  = ExitSuccess
toExitCode False = ExitFailure 1


{- Exit with a success or failure code using a Bool
-}
exitBool :: Bool -> IO ()
exitBool = exitWith . toExitCode


{- This is similar to the for/in/do/done construct in bash with an
   important difference. This action evaluates to ExitFailure 1 if
   *any* of the command executions fails. In bash you only get the
   exit code of the last one.
-}
forSystem :: [String] -> IO ExitCode
forSystem cs = do
   ecs <- mapM system cs
   return $ case all (== ExitSuccess) ecs of
      True  -> ExitSuccess
      False -> ExitFailure 1


{- Some common bash things and their Haskell counterparts:

   bash                             Haskell
   ----                             -------
   dates                            System.Locale, System.Time
      date                             date

      date +"%Y%m%d"                   dateFormat "%Y%m%d"
         result: 20120213
                                    (these two functions above)

   file/dir things                  System.Directory
      $HOME                            getHomeDirectory
      [ -f FILE ]                      doesFileExist FILE
      [ -d DIR ]                       doesDirectoryExist DIR
      pwd                              getCurrentDirectory
      cd DIR                           setCurrentDirectory DIR

   environment variables            System.Environment
      $VAR                             getEnv "VAR"

   arguments                        System.Environment
      arg1=$1                          (arg1 : arg2 : _) <- getArgs
      arg2=$2

   string interpolation             Text.Printf
      "foo $bar ${baz}"                printf "foo %s %d" bar baz

   execution, exit code             System.Cmd
      program -x val arg               ec <- system "program -x val arg"
      ec=$?

   execution, capture stdout        System.Process
      output=$(program -x val arg)     output <- readProcess "program"
                                          ["-x", "val", "arg"]
                                          "stdin data, if desired"

      or use System.Process.readProcessWithExitCode
      :: FilePath -> [String] -> String -> IO (ExitCode, String, String)
         program     args        stdin         exitcode  stdout  stderr

   exiting                          System.Exit
      exit 0                           exitSuccess
      exit 1                           exitFailure
      exit INT                         exitWith $ ExitFailure INT

   regular expressions              Text.Regex
      (see bash docs for =~            mbMatches = matchRegex
       and BASH_REMATCH)                  (mkRegex "a(.)b(.)") string
                                          :: Maybe [String]

-}