summaryrefslogtreecommitdiffstats
path: root/README.BashExtensions
blob: 6c961adaf05b3b9a07972d592b69de61fdbc38c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
April 2008

The following documents the modifications to the haserl parser
when --enable-bash-extensions is enabled.  The following was 
written by Scott, and should not be considered as a core part
of haserl.  (Ask on the mailing list if you need help)

--------------------------------------------------------------

Haserl supports four tags by default. These are generic and
suitable for use with a great variety of shells. If, like
me, you write your scripts with vi (vim) with the syntax
highlighting enabled, then you will have noted how badly
this looks in the editor.

I also prefer the tags to be a bit more intelligent, as I
find it makes the source that much more readable.

To this end I have added the following tags (again, these
are designed with bash in mind, may not work with other
sh-type shells, and are not at all supported if you are
using LUA/LUAC.)


     Tag version:               Expands to:
     ------------------------   ------------------------
     <%if list %>               if [[ list ]] ; then
     <%elif list %>             elif [[ list ]] ; then
     <%else [comment] %>        else [# comment]
     <%endif [comment] %>       fi [# comment]

     <%case word %>             case word in
     <%when pattern %>          pattern)
     <%otherwise [comment] %>   *) : [comment] ;;
     <%endcase [comment] %>     esac [# comment]

     <%while list %>            while list ; do
     <%endwhile %>              done [# comment]

     <%until list %>            until list ; do
     <%enduntil [comment] %>    done [# comment]

     <%for name in word %>      for name in word ; do
     <%endfor [comment] %>      done [# comment]

     <%unless list %>           if [[ ! list ]] ; then
     <%elun list %>             elif [[ ! list ]] ; then
     <%unelse [comment] %>      else [#comment]
     <%endunless [comment %>    fi [# comment]


To simplify parsing, and to reduce confusion when reading
your source, unique words are used. For example, the use of
endwhile, enduntil and endfor instead of done. Also, for
clarity I have used endif/endcase instead of fi/esac.

------
UNLESS
------

Note the last command, the unless...endunless. I find it is
often more clear to express an unless condition than an if
not condition. For example, and to show the streamlining of
code these tags provide:

     <% if [[ ! IsLogged ]] ; then %>
          something
     <% fi %>

This is the improved (IMHO) version:

     <%unless IsLogged %>
          something
     <%endunless %>

Personally, I find no use for "else unless", but I decided
to include it for consistency.

--------------------
CONDITIONAL COMMANDS
--------------------

There is one syntactic problem, concerning the use of the
<%if %>, <%while %>, <%until %> and <%unless %> tags. The
default action is to create a test-style condition; however,
sometime you need to do this:

     <% if grep "text" file &>/dev/null ; then %>

If you simply write this:

     <%if grep "text" file &>/dev/null %>

Then it is expanded to:

     if [[ grep "text" file &>/dev/null ]] %>

That is obviously incorrect. To allow for this the parser
provides a bit of syntactic sugar. It checks the first
character of the expression list and if it is, then it
rewrites the list as a command. For example:

     <%if |grep "text" file &>/dev/null %>

Becomes:

     if grep "text" file &>/dev/null ; then

--------------
CASE STATMENTS
--------------

The case statement provided another challenge, namely how to
handle the pesky ;; required at the end of each case. I am
not a C person, so personally I find the next instance of a
case to be sufficient to terminate the first. Given that the
shell version of case can accept multiple conditions, there
is really no reason to worry with cases falling through as
they do in C. In other words, I'm all for ditching the ;;
construct altogether.

So I did.

The enhanced <%case %> tag operates without an explicit ;;
being required. It is perhaps easier to show than explain,
so here's an example:

     <%case "$FRUIT" %>
     <%when apple %>
          echo "It's an apple!"
     <%when orange %>
          echo "It's an orange!"
     <%otherwise something else %>
          echo "Not what I expected."
     <%endcase %>

The parser renders this as follows:

     case "$FRUIT" in
     "\000\012\004") :
     ;;
     apple)
     echo "It's an apple!"
     ;;
     orange)
     echo "It's an orange!"
     ;;
     *) # something else
     echo "Not what I expected."
     ;;
     esac

Note the odd first case. The parser inserts this so ensure
that each subsequent when/otherwise/endcase can be preceded
by ;;. This eliminates the need to remember the ;;, and I
believe makes for cleaner code. There is, of course, a small
performance penalty for always having to evaluate this extra
case. In real life I find this not to be a problem, however,
if you are processing inside a loop and expect a large chunk
of items, then it is something to be aware of.