1 #!/bin/bash
2 #
3 # Test set flags, sh flags.
4
5 ### can continue after unknown option
6 # dash and mksh make this a fatal error no matter what.
7 set -o errexit
8 set -o STRICT || true # unknown option
9 echo hello
10 # stdout: hello
11 # status: 0
12 # BUG dash/mksh stdout-json: ""
13 # BUG dash status: 2
14 # BUG mksh status: 1
15
16 ### set with both options and argv
17 set -o errexit a b c
18 echo "$@"
19 false
20 echo done
21 # stdout: a b c
22 # status: 1
23
24 ### nounset
25 echo "[$unset]"
26 set -o nounset
27 echo "[$unset]"
28 echo end # never reached
29 # stdout: []
30 # status: 1
31 # OK dash status: 2
32
33 ### -u is nounset
34 echo "[$unset]"
35 set -u
36 echo "[$unset]"
37 echo end # never reached
38 # stdout: []
39 # status: 1
40 # OK dash status: 2
41
42 ### reset option with long flag
43 set -o errexit
44 set +o errexit
45 echo "[$unset]"
46 # stdout: []
47 # status: 0
48
49 ### reset option with short flag
50 set -u
51 set +u
52 echo "[$unset]"
53 # stdout: []
54 # status: 0
55
56 ### sh -c
57 $SH -c 'echo hi'
58 # stdout: hi
59 # status: 0
60
61 ### -n for no execution (useful with --ast-output)
62 # NOTE: set +n doesn't work because nothing is executed!
63 echo 1
64 set -n
65 echo 2
66 set +n
67 echo 3
68 # stdout-json: "1\n"
69 # status: 0
70
71 ### xtrace
72 echo 1
73 set -o xtrace
74 echo 2
75 # stdout-json: "1\n2\n"
76 # stderr: + echo 2
77
78 ### errexit aborts early
79 set -o errexit
80 false
81 echo done
82 # stdout-json: ""
83 # status: 1
84
85 ### errexit aborts early on pipeline
86 set -o errexit
87 echo hi | grep nonexistent
88 echo two
89 # stdout-json: ""
90 # status: 1
91
92 ### errexit with { }
93 # This aborts because it's not part of an if statement.
94 set -o errexit
95 { echo one; false; echo two; }
96 # stdout: one
97 # status: 1
98
99 ### errexit with if and { }
100 set -o errexit
101 if { echo one; false; echo two; }; then
102 echo three
103 fi
104 echo four
105 # stdout-json: "one\ntwo\nthree\nfour\n"
106 # status: 0
107
108 ### errexit with ||
109 set -o errexit
110 echo hi | grep nonexistent || echo ok
111 # stdout: ok
112 # status: 0
113
114 ### errexit with &&
115 set -o errexit
116 echo ok && echo hi | grep nonexistent
117 # stdout: ok
118 # status: 1
119
120 ### errexit with !
121 set -o errexit
122 echo one
123 ! true
124 echo two
125 ! false
126 echo three
127 # stdout-json: "one\ntwo\nthree\n"
128 # status: 0
129
130 ### errexit with while/until
131 set -o errexit
132 while false; do
133 echo ok
134 done
135 until false; do
136 echo ok # do this once then exit loop
137 break
138 done
139 # stdout: ok
140 # status: 0
141
142 ### errexit with (( ))
143 # from http://mywiki.wooledge.org/BashFAQ/105, this changed between verisons.
144 set -o errexit
145 i=0
146 (( i++ ))
147 echo done
148 # stdout-json: ""
149 # status: 1
150 # N-I dash status: 127
151 # N-I dash stdout-json: ""
152
153 ### errexit with subshell
154 set -o errexit
155 ( echo one; false; echo two; )
156 # stdout: one
157 # status: 1
158
159 ### errexit with command sub
160 # This is the bash-specific bug here:
161 # https://blogs.janestreet.com/when-bash-scripts-bite/
162 set -o errexit
163 s=$(echo one; false; echo two;)
164 echo "$s"
165 # stdout-json: ""
166 # status: 1
167 # BUG bash status: 0
168 # BUG bash stdout-json: "one\ntwo\n"
169
170 ### errexit with local
171 # I've run into this problem a lot.
172 # https://blogs.janestreet.com/when-bash-scripts-bite/
173 set -o errexit
174 f() {
175 echo good
176 local x=$(echo bad; false)
177 echo $x
178 }
179 f
180 # stdout-json: "good\n"
181 # status: 1
182 # BUG bash/dash/mksh stdout-json: "good\nbad\n"
183 # BUG bash/dash/mksh status: 0
184
185 ### setting errexit while it's being ignored
186 # ignored and then set again
187 set -o errexit
188 # osh aborts early here
189 if { echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; }; then
190 echo 5;
191 fi
192 echo 6
193 false # this is the one that makes other shells fail
194 echo 7
195 # status: 1
196 # stdout-json: "1\n2\n"
197 # OK dash/bash/mksh stdout-json: "1\n2\n3\n4\n5\n6\n"
198
199 ### setting errexit in a subshell works but doesn't affect parent shell
200 ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; )
201 echo 5
202 false
203 echo 6
204 # stdout-json: "1\n2\n3\n5\n6\n"
205 # status: 0
206
207 ### setting errexit while it's being ignored in a subshell
208 set -o errexit
209 if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
210 echo 5;
211 fi
212 echo 6 # This is executed because the subshell just returns false
213 false
214 echo 7
215 # status: 1
216 # stdout-json: "1\n2\n6\n"
217 # OK dash/bash/mksh stdout-json: "1\n2\n3\n4\n5\n6\n"
218
219 ### errexit double quard
220 # OSH bug fix. ErrExit needs a counter, not a boolean.
221 set -o errexit
222 if { ! false; false; true; } then
223 echo true
224 fi
225 false
226 echo done
227 # status: 1
228 # stdout-json: "true\n"
229
230 ### pipefail
231 # NOTE: the sleeps are because osh can fail non-deterministically because of a
232 # bug. Same problem as PIPESTATUS.
233 { sleep 0.01; exit 9; } | { sleep 0.02; exit 2; } | { sleep 0.03; exit 0; }
234 echo $?
235 set -o pipefail
236 { sleep 0.01; exit 9; } | { sleep 0.02; exit 2; } | { sleep 0.03; exit 0; }
237 echo $?
238 # stdout-json: "0\n2\n"
239 # status: 0
240 # N-I dash stdout-json: "0\n"
241 # N-I dash status: 2