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 |