1 #!/usr/bin/env bash
2 #
3 # Usage:
4 # ./errexit.test.sh <function name>
5
6 ### errexit aborts early
7 set -o errexit
8 false
9 echo done
10 # stdout-json: ""
11 # status: 1
12
13 ### errexit for nonexistent command
14 set -o errexit
15 nonexistent__ZZ
16 echo done
17 # stdout-json: ""
18 # status: 127
19
20 ### errexit aborts early on pipeline
21 set -o errexit
22 echo hi | grep nonexistent
23 echo two
24 # stdout-json: ""
25 # status: 1
26
27 ### errexit with { }
28 # This aborts because it's not part of an if statement.
29 set -o errexit
30 { echo one; false; echo two; }
31 # stdout: one
32 # status: 1
33
34 ### errexit with if and { }
35 set -o errexit
36 if { echo one; false; echo two; }; then
37 echo three
38 fi
39 echo four
40 # stdout-json: "one\ntwo\nthree\nfour\n"
41 # status: 0
42
43 ### errexit with ||
44 set -o errexit
45 echo hi | grep nonexistent || echo ok
46 # stdout: ok
47 # status: 0
48
49 ### errexit with &&
50 set -o errexit
51 echo ok && echo hi | grep nonexistent
52 # stdout: ok
53 # status: 1
54
55 ### errexit test && -- from gen-module-init
56 set -o errexit
57 test "$mod" = readline && echo "#endif"
58 echo status=$?
59 # stdout: status=1
60
61 ### errexit test && and fail
62 set -o errexit
63 test -n X && false
64 echo status=$?
65 # stdout-json: ""
66 # status: 1
67
68 ### errexit and loop
69 set -o errexit
70 for x in 1 2 3; do
71 test $x = 2 && echo "hi $x"
72 done
73 # stdout: hi 2
74 # status: 1
75
76 ### errexit and brace group { }
77 set -o errexit
78 { test no = yes && echo hi; }
79 echo status=$?
80 # stdout: status=1
81
82 ### errexit and time { }
83 set -o errexit
84 time false
85 echo status=$?
86 # status: 1
87
88 ### errexit with !
89 set -o errexit
90 echo one
91 ! true
92 echo two
93 ! false
94 echo three
95 # stdout-json: "one\ntwo\nthree\n"
96 # status: 0
97
98 ### errexit with ! and ;
99 # AST has extra Sentence nodes; there was a REGRESSION here.
100 set -o errexit; echo one; ! true; echo two; ! false; echo three
101 # stdout-json: "one\ntwo\nthree\n"
102 # status: 0
103
104 ### errexit with while/until
105 set -o errexit
106 while false; do
107 echo ok
108 done
109 until false; do
110 echo ok # do this once then exit loop
111 break
112 done
113 # stdout: ok
114 # status: 0
115
116 ### errexit with (( ))
117 # from http://mywiki.wooledge.org/BashFAQ/105, this changed between verisons.
118 # ash says that 'i++' is not found, but it doesn't exit. I guess this is the
119 # subshell problem?
120 set -o errexit
121 i=0
122 (( i++ ))
123 echo done
124 # stdout-json: ""
125 # status: 1
126 # N-I dash status: 127
127 # N-I dash stdout-json: ""
128 # BUG ash status: 0
129 # BUG ash stdout: done
130
131 ### errexit with subshell
132 set -o errexit
133 ( echo one; false; echo two; )
134 # stdout: one
135 # status: 1
136
137 ### errexit with command sub
138 # This is the bash-specific bug here:
139 # https://blogs.janestreet.com/when-bash-scripts-bite/
140 set -o errexit
141 s=$(echo one; false; echo two;)
142 echo "$s"
143 # stdout-json: ""
144 # status: 1
145 # BUG ash/bash status: 0
146 # BUG ash/bash stdout-json: "one\ntwo\n"
147
148 ### errexit with local
149 # I've run into this problem a lot.
150 # https://blogs.janestreet.com/when-bash-scripts-bite/
151 set -o errexit
152 f() {
153 echo good
154 local x=$(echo bad; false)
155 echo $x
156 }
157 f
158 # stdout-json: "good\n"
159 # status: 1
160 # BUG bash/dash/mksh/ash stdout-json: "good\nbad\n"
161 # BUG bash/dash/mksh/ash status: 0
162
163 ### setting errexit while it's being ignored
164 # ignored and then set again
165 set -o errexit
166 # osh aborts early here
167 if { echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; }; then
168 echo 5;
169 fi
170 echo 6
171 false # this is the one that makes other shells fail
172 echo 7
173 # status: 1
174 # stdout-json: "1\n2\n"
175 # OK dash/bash/mksh/ash stdout-json: "1\n2\n3\n4\n5\n6\n"
176
177 ### setting errexit in a subshell works but doesn't affect parent shell
178 ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; )
179 echo 5
180 false
181 echo 6
182 # stdout-json: "1\n2\n3\n5\n6\n"
183 # status: 0
184
185 ### setting errexit while it's being ignored in a subshell
186 set -o errexit
187 if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
188 echo 5;
189 fi
190 echo 6 # This is executed because the subshell just returns false
191 false
192 echo 7
193 # status: 1
194 # stdout-json: "1\n2\n6\n"
195 # OK dash/bash/mksh/ash stdout-json: "1\n2\n3\n4\n5\n6\n"
196
197 ### errexit double quard
198 # OSH bug fix. ErrExit needs a counter, not a boolean.
199 set -o errexit
200 if { ! false; false; true; } then
201 echo true
202 fi
203 false
204 echo done
205 # status: 1
206 # stdout-json: "true\n"