1 #!/bin/bash
2 #
3 # Cases relevant to shopt -s strict-errexit in OSH.
4 #
5 # Summary:
6 # - errexit is reset to false in ash/bash -- completely ignored!
7 # - local assignment is different than global! The exit code and errexit
8 # behavior are different because the concept of the "last command" is
9 # different.
10 # - ash has copied bash behavior!
11
12 #### command sub: errexit is NOT inherited
13
14 # This is the bash-specific bug here:
15 # https://blogs.janestreet.com/when-bash-scripts-bite/
16 # See inherit_errexit below.
17 #
18 # I remember finding a script that relies on bash's bad behavior, so OSH copies
19 # it. Instead strict-errexit, is recommended.
20
21 set -o errexit
22 echo $(echo one; false; echo two) # bash/ash keep going
23 echo status=$?
24 ## STDOUT:
25 one two
26 status=0
27 ## END
28 # dash and mksh: inner shell aborts, but outer one keeps going!
29 ## OK dash/mksh STDOUT:
30 one
31 status=0
32 ## END
33
34 #### command sub: errexit not ignored with strict-errexit
35 set -o errexit
36
37 # bash implements inherit_errexit, but it's not as strict as OSH.
38 shopt -s inherit_errexit || true
39
40 shopt -s strict-errexit || true
41 echo zero
42 echo $(echo one; false; echo two) # bash/ash keep going
43 echo status=$?
44 ## STDOUT:
45 zero
46 ## END
47 ## status: 1
48 ## N-I dash/mksh/bash status: 0
49 ## N-I dash/mksh/bash STDOUT:
50 zero
51 one
52 status=0
53 ## END
54 ## N-I ash status: 0
55 ## N-I ash STDOUT:
56 zero
57 one two
58 status=0
59 ## END
60
61 #### command sub: last command fails but keeps going and exit code is 0
62 set -o errexit
63 echo $(echo one; false) # we lost the exit code
64 echo status=$?
65 ## STDOUT:
66 one
67 status=0
68 ## END
69
70 #### global assignment with command sub: middle command fails
71 set -o errexit
72 s=$(echo one; false; echo two;)
73 echo "$s"
74 ## status: 0
75 ## STDOUT:
76 one
77 two
78 ## END
79 # dash and mksh: whole thing aborts!
80 ## OK dash/mksh stdout-json: ""
81 ## OK dash/mksh status: 1
82
83 #### global assignment with command sub: last command fails and it aborts
84 set -o errexit
85 s=$(echo one; false)
86 echo status=$?
87 ## stdout-json: ""
88 ## status: 1
89
90 #### local: middle command fails and keeps going
91 set -o errexit
92 f() {
93 echo good
94 local x=$(echo one; false; echo two)
95 echo status=$?
96 echo $x
97 }
98 f
99 ## STDOUT:
100 good
101 status=0
102 one two
103 ## END
104 # for dash and mksh, the INNER shell aborts, but the outer one keeps going!
105 ## OK dash/mksh STDOUT:
106 good
107 status=0
108 one
109 ## END
110
111 #### local: last command fails and also keeps going
112 set -o errexit
113 f() {
114 echo good
115 local x=$(echo one; false)
116 echo status=$?
117 echo $x
118 }
119 f
120 ## STDOUT:
121 good
122 status=0
123 one
124 ## END
125
126 #### local and strict-errexit
127 # I've run into this problem a lot.
128 set -o errexit
129 shopt -s strict-errexit || true # ignore error
130 f() {
131 echo good
132 local x=$(echo one; false; echo two)
133 echo status=$?
134 echo $x
135 }
136 f
137 ## status: 1
138 ## STDOUT:
139 good
140 ## END
141 ## N-I bash/ash status: 0
142 ## N-I bash/ash STDOUT:
143 good
144 status=0
145 one two
146 ## END
147 ## N-I dash/mksh status: 0
148 ## N-I dash/mksh STDOUT:
149 good
150 status=0
151 one
152 ## END
153
154 #### global assignment when last status is failure
155 # this is a bug I introduced
156 set -o errexit
157 [ -n "${BUILDDIR+x}" ] && _BUILDDIR=$BUILDDIR
158 BUILDDIR=${_BUILDDIR-$BUILDDIR}
159 echo status=$?
160 ## STDOUT:
161 status=0
162 ## END
163
164 #### global assignment when last status is failure
165 # this is a bug I introduced
166 set -o errexit
167 x=$(false) || true # from abuild
168 [ -n "$APORTSDIR" ] && true
169 BUILDDIR=${_BUILDDIR-$BUILDDIR}
170 echo status=$?
171 ## STDOUT:
172 status=0
173 ## END