diff --git a/Language/Bash.hs b/Language/Bash.hs
--- a/Language/Bash.hs
+++ b/Language/Bash.hs
@@ -15,6 +15,8 @@
   , Language.Bash.Syntax.identifier
   , Language.Bash.Syntax.SpecialVar()
   , Language.Bash.Syntax.specialVar
+  , Language.Bash.Syntax.VarName(..)
+  , Language.Bash.Syntax.varName
   , Language.Bash.Syntax.Redirection(..)
   , Language.Bash.Syntax.FileDescriptor(..)
   , Language.Bash.PrettyPrinter.PP(..)
diff --git a/Language/Bash/PrettyPrinter.hs b/Language/Bash/PrettyPrinter.hs
--- a/Language/Bash/PrettyPrinter.hs
+++ b/Language/Bash/PrettyPrinter.hs
@@ -89,7 +89,7 @@
                                    outdent
     NoOp msg | null msg     ->  word ":"
              | otherwise    ->  word ":" >> (word . Esc.bytes . Esc.bash) msg
-    Bang t                  ->  hang "!"      >> binGrp t >> outdent
+    Bang t                  ->  hangWord "!" >> binGrp t >> outdent
     AndAnd t t'             ->  binGrp t >> word "&&" >> nl >> binGrp t'
     OrOr t t'               ->  binGrp t >> word "||" >> nl >> binGrp t'
     Pipe t t'               ->  binGrp t >> word "|"  >> nl >> binGrp t'
@@ -99,26 +99,28 @@
     Subshell t              ->  roundOpen >> pp t     >> roundClose >> outdent
     Function ident t        ->  do wordcat ["function ", bytes ident]
                                    inword " {" >> pp t >> outword "}"
-    IfThen t t'             ->  do hang "if" >> pp t   >> outdent   >> nl
+    IfThen t t'             ->  do hangWord "if" >> pp t  >> outdent >> nl
                                    inword "then" >> pp t' >> outword "fi"
-    IfThenElse t t' t''     ->  do hang "if" >> pp t   >> outdent   >> nl
+    IfThenElse t t' t''     ->  do hangWord "if" >> pp t >> outdent >> nl
                                    inword "then"       >> pp t'     >> outdent
                                    nl
                                    inword "else"       >> pp t''
                                    outword "fi"
-    For var vals t          ->  do hang (concat ["for ", bytes var, " in"])
+    For var vals t          ->  do hangWord (concat ["for ", bytes var, " in"])
                                    mapM_ breakline vals
                                    outdent >> nl
                                    inword "do" >> pp t >> outword "done"
     Case expr cases         ->  do word "case" >> pp expr >> inword "in"
                                    mapM_ case_clause cases
                                    outword "esac"
-    While t t'              ->  do hang "while" >> pp t >> outdent >> nl
+    While t t'              ->  do hangWord "while" >> pp t >> outdent >> nl
                                    inword "do" >> pp t' >> outword "done"
-    Until t t'              ->  do hang "until" >> pp t >> outdent >> nl
+    Until t t'              ->  do hangWord "until" >> pp t >> outdent >> nl
                                    inword "do" >> pp t' >> outword "done"
 --  BraceBrace _            ->  error "[[ ]]"
-    VarAssign var val       ->  wordcat [bytes var, "=", bytes val]
+--  VarAssign var val       ->  wordcat [bytes var, "=", bytes val]
+    VarAssign var val       ->  do hang (bytes var `mappend` "=")
+                                   pp val >> outdent
     ArrayDecl var exprs     ->  do hangcat ["declare -a ", bytes var, "=("]
                                    array_pp pp exprs >> word ")"
                                    nl >> outdent
@@ -137,7 +139,7 @@
     Redirect stmt d fd t    ->  do redirectGrp stmt
                                    word (render_redirect d fd t)
 
-hangcat                      =  hang . concat
+hangcat                      =  hangWord . concat
 
 array_pp _   [   ]           =  return ()
 array_pp ppF (h:t)           =  ppF h >> mapM_ ppFNL t
@@ -146,7 +148,7 @@
 
 keyset (key, val)            =  wordcat ["[", bytes key, "]=", bytes val]
 
-case_clause (ptrn, stmt)     =  do hang (bytes ptrn `append` ") ")
+case_clause (ptrn, stmt)     =  do hangWord (bytes ptrn `append` ") ")
                                    pp stmt >> word ";;" >> outdent >> nl
 
 render_redirect direction fd target =
@@ -170,7 +172,7 @@
 trimPrinter                 ::  Trim -> ByteString
 trimPrinter ShortestLeading  =  "#"
 trimPrinter LongestLeading   =  "##"
-trimPrinter ShortestTrailing = "%"
+trimPrinter ShortestTrailing =  "%"
 trimPrinter LongestTrailing  =  "%%"
 
 binGrp a@(Annotated _ stmt)  =  case stmt of
@@ -190,7 +192,7 @@
 breakline printable          =  do
   PPState{..}               <-  get
   when (columns + maxLineLength printed + 1 > 79 && columns /= sum indents)
-       (opM [Word "\\", Newline])
+       (opM [Bytes "\\", Newline])
   pp printable
  where
   printed                    =  bytes printable
@@ -209,7 +211,7 @@
 
 inlineEvalPrinter open close ann =  do
   indentPadToNextWord
-  hang open
+  hangWord open
   pp ann
   word close
   outdent >> outdent
diff --git a/Language/Bash/PrettyPrinter/State.hs b/Language/Bash/PrettyPrinter/State.hs
--- a/Language/Bash/PrettyPrinter/State.hs
+++ b/Language/Bash/PrettyPrinter/State.hs
@@ -25,13 +25,15 @@
                                         , curly :: [()]
                                         , round :: [()]
                                         , columns :: Word
+                                        , separated :: Bool
                                         , string :: Builder }
 instance Show PPState where
-  show PPState{..}           =  "PPState { indents=" ++ show indents
-                                      ++ " curly="   ++ show curly
-                                      ++ " round="   ++ show round
-                                      ++ " columns=" ++ show columns
-                                      ++ " string="  ++ "..." ++ " }"
+  show PPState{..}           =  "PPState { indents="   ++ show indents
+                                      ++ " curly="     ++ show curly
+                                      ++ " round="     ++ show round
+                                      ++ " columns="   ++ show columns
+                                      ++ " separated=" ++ show separated
+                                      ++ " string="    ++ "..." ++ " }"
 
 {-| Produce a builder from a pretty printer state computation.
  -}
@@ -44,15 +46,16 @@
 {-| Pretty printer state starting on a new line indented to the given column.
  -}
 nlCol                       ::  Word -> PPState
-nlCol w                      =  PPState [w] [()] [()] 0 Builder.empty
+nlCol w                      =  PPState [w] [()] [()] 0 True Builder.empty
 
 
 {-| Operations we can perform while pretty printing.
  -}
 data PPOp                    =  Indent Word -- ^ Indent by N spaces.
-                             |  Outdent -- ^ Remove and indentation level.
-                             |  Word ByteString -- ^ Add a word to a line.
+                             |  Outdent -- ^ Remove an indentation level.
+                             |  Bytes ByteString -- ^ Add bytes to the script.
                              |  Newline -- ^ Move to newline.
+                             |  WordSeparator -- ^ Separate words with space.
                              |  Curly Bool -- ^ Introduce a level of braces.
                              |  Round Bool -- ^ Introduce a level of parens.
 
@@ -64,29 +67,38 @@
   Indent w                  ->  state { indents = w:indents }
   Outdent                   ->  state { indents = tSafe indents }
   Curly f | f               ->  state { indents = 2:indents, curly = ():curly
-                                      , string = curly_s, columns = columns+2 }
+                                      , string = curly_s, columns = columns+2
+                                      , separated = True }
           | otherwise       ->  state { indents = tSafe indents
-                                      , curly = tSafe curly, string = s_curly }
+                                      , curly = tSafe curly, string = s_curly
+                                      , separated = False }
   Round f | f               ->  state { indents = 2:indents, round = ():round
-                                      , string = round_s, columns = columns+2 }
+                                      , string = round_s, columns = columns+2
+                                      , separated = True }
           | otherwise       ->  state { indents = tSafe indents
-                                      , round = tSafe round, string = s_round }
-  Newline | columns == 0    ->  state
-          | otherwise       ->  state { string = sNL, columns = 0 }
-  Word b                    ->  state { string = s', columns = c' }
+                                      , round = tSafe round, string = s_round
+                                      , separated = False }
+  WordSeparator             ->  state { separated = False }
+  Newline | columns == 0    ->  state { separated = True }
+          | otherwise       ->  state { string = sNL, columns = 0
+                                      , separated = True          }
+  Bytes b                   ->  state { string = s', columns = c' }
    where
-    c'                       =  columns + cast (length padded)
-    s'                       =  string `mappend` Builder.fromByteString padded
-    dent                     =  cast (sum indents)
-    padded | columns == 0    =  replicate dent ' ' `append` b
-           | otherwise       =  ' ' `cons` b
+    c'                       =  columns + cast (length padded + length sSep)
+    s'                       =  sappend padded
+    dent                     =  cast (sum indents) `replicate` ' '
+    padded | columns == 0    =  dent `mappend` b
+           | otherwise       =  b
  where
+  sappend = mappend string . Builder.fromByteString . mappend sSep
   tSafe list                 =  if null list then [] else List.tail list
-  sNL                        =  string `mappend` Builder.fromByteString "\n"
-  curly_s                    =  Builder.fromByteString "{" `mappend` string
-  s_curly                    =  string `mappend` Builder.fromByteString " ;}"
-  round_s                    =  Builder.fromByteString "(" `mappend` string
-  s_round                    =  string `mappend` Builder.fromByteString " )"
+  sNL                        =  sappend "\n"
+  curly_s                    =  sappend "{"
+  s_curly                    =  sappend ";}"
+  round_s                    =  sappend "("
+  s_round                    =  sappend ")"
+  sSep | not separated       =  " "
+       | otherwise           =  ""
 
 opM                         ::  [PPOp] -> State PPState ()
 opM                          =  mapM_ (modify . flip op)
@@ -94,33 +106,52 @@
 nl                          ::  State PPState ()
 nl                           =  opM [Newline]
 hang                        ::  ByteString -> State PPState ()
-hang b                       =  opM [Word b, Indent (cast (length b) + 1)]
+hang b                       =  opM [Bytes b, Indent (cast (length b))]
+hangWord                    ::  ByteString -> State PPState ()
+hangWord b = opM [Bytes b, Indent (cast (length b) + 1), WordSeparator]
 word                        ::  ByteString -> State PPState ()
-word b                       =  opM [Word b]
+word b                       =  opM [Bytes b, WordSeparator]
 wordcat                     ::  [ByteString] -> State PPState ()
 wordcat                      =  word . concat
 outdent                     ::  State PPState ()
 outdent                      =  opM [Outdent]
 inword                      ::  ByteString -> State PPState ()
-inword b                     =  opM [Word b, Indent 2, Newline]
+inword b                     =  opM [Bytes b, Indent 2, Newline]
 outword                     ::  ByteString -> State PPState ()
-outword b                    =  opM [Newline, Outdent, Word b]
+outword b                    =  opM [Newline, Outdent, Bytes b, WordSeparator]
 curlyOpen                   ::  State PPState ()
-curlyOpen                    =  opM [Curly True]
+curlyOpen                    =  opM [Curly True, WordSeparator]
 curlyClose                  ::  State PPState ()
-curlyClose                   =  opM [Curly False]
+curlyClose                   =  opM [Curly False, WordSeparator]
 roundOpen                   ::  State PPState ()
-roundOpen                    =  opM [Round True]
+roundOpen                    =  opM [Round True, WordSeparator]
 roundClose                  ::  State PPState ()
-roundClose                   =  opM [Round False]
+roundClose                   =  opM [Round False, WordSeparator]
+
+{-| This procedure is used in printing statements within evals, to set up
+    indentation correctly for lines /following/ the first line. It ensures
+    that the second and following lines are printed aligned with the first
+    character of the first line of the statement, not the first character of
+    the @$(@, @>(@ or @<(@ enclosing the eval.
+ -}
 indentPadToNextWord         ::  State PPState ()
 indentPadToNextWord          =  do
   PPState{..}               <-  get
-  let x                      =  sum indents
-      columns'               =  columns + 1
-      indent | columns' > x  =  columns' - x
+  let i                      =  sum indents
+      columns' | separated   =  columns
+               | otherwise   =  columns + 1
+      indent | columns' > i  =  columns' - i
              | otherwise     =  0
   opM [Indent indent]
 
 cast                         =  fromIntegral
+
+-- Debug renderer.
+renderIndents indents        =  (mconcat . Prelude.reverse)
+                                (Prelude.map prettify_indent indents)
+ where
+  prettify_indent 0          =  ""
+  prettify_indent 1          =  "|"
+  prettify_indent 2          =  "-|"
+  prettify_indent n          =  "-" `mappend` prettify_indent (n-1)
 
diff --git a/bash.cabal b/bash.cabal
--- a/bash.cabal
+++ b/bash.cabal
@@ -1,5 +1,5 @@
 name                          : bash
-version                       : 0.1.1
+version                       : 0.1.2
 category                      : Language
 license                       : BSD3
 license-file                  : LICENSE
diff --git a/tests.bash b/tests.bash
--- a/tests.bash
+++ b/tests.bash
@@ -57,7 +57,7 @@
 #> let ls = Annotated () . SimpleCommand "ls" . (:[])
 #> let echo = Annotated () . SimpleCommand "echo"
 #> let vRANDOM = VarIdent "RANDOM"
-#> let randomLT_ n = SimpleCommand "[" [ReadVar vRANDOM), "-lt", n, "]"]
+#> let randomLT_ n = SimpleCommand "[" [ReadVar vRANDOM, "-lt", n, "]"]
 #> let randomLT n = Annotated () (randomLT_ n)
 #> let commented a b = Annotated (Lines a b)
 
@@ -288,4 +288,58 @@
 patterns[trailing]=ef
 echo "${string#"${patterns[leading]}"}" "${string%"${patterns[trailing]}"}" \
      "${string#*/}" "${string##*/}" "${string%/*}" "${string%%/*}"
+
+#redirectIn  y c = Redirect (ann_ c) In  0 (Left y)
+#> let redirectI f stmt = Redirect (Annotated () stmt) In  0 (Left f)
+#> let redirectO f stmt = Redirect (Annotated () stmt) Out 1 (Left f)
+#> let redirectE f stmt = Redirect (Annotated () stmt) Out 2 (Left f)
+#> let clauseSimple ex stmt = (ex, Annotated () stmt)
+#> let echo_ = SimpleCommand "echo"
+#> let echo__ t = Sequence (Annotated () (echo_ [t])) (Annotated () (echo_ [t]))
+#> let c__ = clauseSimple "w" (echo_ ["->w"])
+##> let c2  = clauseSimple "x" (echo__ "->x")
+#> let c2  = clauseSimple "x" ((Bang . Annotated()) (echo__ "->x"))
+##> let c2  = clauseSimple "x" ((redirectI "i") (echo__ "->x"))
+#> let cIO = clauseSimple "y" ((redirectO "o" . redirectI "i") (echo_ ["->y"]))
+#> let cI_ = clauseSimple "z" (redirectI "i" (echo_ ["->z"]))
+#> let read_1 = ReadVarSafe (VarSpecial Dollar1)
+#> let caseClauseRedirect = Annotated () (Case read_1 [c__, c2, cI_, cIO])
+#> render caseClauseRedirect
+case "${1:-}" in
+  w)  echo $'->w' ;;
+  x)  ! { echo $'->x'
+          echo $'->x' ;} ;;
+  z)  echo $'->z' 0<i ;;
+esac
+
+#> let echo2 = Annotated () ((Bang . Annotated()) (echo__ "->x"))
+#> let echoFor = Annotated () $ echo2 `AndAnd` forStmt
+#> render echoFor
+{ ! { echo $'->x'
+      echo $'->x' ;} ;} &&
+for x in /var/log/apache2/*.log /var/log/httpd
+do
+  ls "${x:-}" ||
+  echo $'Failed to `ls\':' "${x:-}" 1>&2
+done
+
+#> let (var :: Identifier) = "var"
+#> let setEVAL = Annotated () (VarAssign var (Eval whileStmt))
+#> render setEVAL
+var="$( while if $'[' "$RANDOM" -lt 40000 $']' 
+              then
+                $'[' "$RANDOM" -lt 10000 $']' 
+              else
+                $'[' "$RANDOM" -lt 45000 $']' 
+              fi 
+        do
+          echo ok 
+        done )"
+
+#> let (var :: Identifier) = "var"
+#> let evalUnquotedEcho = (EvalUnquoted . Annotated ()) (echo__ "text")
+#> let setEVALUNQUOTED = Annotated () (VarAssign var evalUnquotedEcho)
+#> render setEVALUNQUOTED
+var=$( echo text
+       echo text )
 
