Shell script is the lingua franca of Unix, it's available everywhere and often the only reasonable choice to Get Stuff Done. But it's also clumsy and it's easy to write unsafe shell scripts, that forget to quote variables, typo names of functions, etc.
Wouldn't it be nice if we could write code in some better language, that generated nicely formed shell scripts and avoided such gotchas? Today, I've built a Haskell monad that can generate shell code.
Here's a fairly involved example. This demonstrates several features,
including the variadic cmd
, the ability to define shell functions,
to bind and use shell variables, to build pipes (with the -:-
operator),
and to factor out generally useful haskell functions like pipeLess
and promptFor
...
santa = script $ do
hohoho <- func $
cmd "echo" "Ho, ho, ho!" "Merry xmas!"
hohoho
promptFor "What's your name?" $ \name -> pipeLess $ do
cmd "echo" "Let's see what's in" (val name <> quote "'s") "stocking!"
forCmd (cmd "ls" "-1" (quote "/home/" <> val name)) $ \f -> do
cmd "echo" "a shiny new" f
hohoho
cmd "rm" "/table/cookies" "/table/milk"
hohoho
pipeLess :: Script () -> Script ()
pipeLess c = c -|- cmd "less"
promptFor :: T.Text -> (Var -> Script ()) -> Script ()
promptFor prompt cont = do
cmd "printf" (prompt <> " ")
var <- newVar "prompt"
readVar var
cont var
When run, that haskell program generates this shell code. Which, while machine-generated, has nice indentation, and is generally pretty readable.
#!/bin/sh
f1 () { :
echo 'Ho, ho, ho!' 'Merry xmas!'
}
f1
printf 'What'"'"'s your name? '
read '_prompt1'
(
echo 'Let'"'"'s see what'"'"'s in' "$_prompt1"''"'"'s' 'stocking!'
for _x1 in $(ls '-1' '/home/'"$_prompt1")
do :
echo 'a shiny new' "$_x1"
f1
done
) | (
less
)
rm '/table/cookies' '/table/milk'
f1
Santa has already uploaded shell-monad to hackage and git.
There's a lot of things that could be added to this library
(if
, while
, redirection, etc), but I can already see using
it in various parts of propellor and git-annex that need to generate
shell code.
Do you have an issue tracker for shell monad? It seems that
generates code
instead of the working
or
Thanks for reporting, I'll fix this in 0.6.3.
The best way to report bugs in shell-monad currently is to email me.