1 |
#!/usr/bin/env bash |
2 |
# |
3 |
# Test set flags, sh flags. |
4 |
|
5 |
#### $- with -c |
6 |
# dash's behavior seems most sensible here? |
7 |
$SH -o nounset -c 'echo $-' |
8 |
## stdout: u |
9 |
## OK bash stdout: huBc |
10 |
## OK mksh stdout: uhc |
11 |
## status: 0 |
12 |
|
13 |
#### $- with pipefail |
14 |
set -o pipefail -o nounset |
15 |
echo $- |
16 |
## stdout: u |
17 |
## status: 0 |
18 |
## OK bash stdout: huBs |
19 |
## OK mksh stdout: ush |
20 |
## N-I dash stdout-json: "" |
21 |
## N-I dash status: 2 |
22 |
|
23 |
#### $- with interactive shell |
24 |
$SH -c 'echo $-' | grep i || echo FALSE |
25 |
$SH -i -c 'echo $-' | grep -q i && echo TRUE |
26 |
## STDOUT: |
27 |
FALSE |
28 |
TRUE |
29 |
## END |
30 |
|
31 |
#### sh -c |
32 |
$SH -c 'echo hi' |
33 |
## stdout: hi |
34 |
## status: 0 |
35 |
|
36 |
#### empty -c input |
37 |
# had a bug here |
38 |
$SH -c '' |
39 |
## stdout-json: "" |
40 |
## status: 0 |
41 |
|
42 |
#### empty stdin |
43 |
# had a bug here |
44 |
echo -n '' | $SH |
45 |
## stdout-json: "" |
46 |
## status: 0 |
47 |
|
48 |
#### args are passed |
49 |
$SH -c 'argv.py "$@"' dummy a b |
50 |
## stdout: ['a', 'b'] |
51 |
|
52 |
#### args that look like flags are passed after script |
53 |
script=$TMP/sh1.sh |
54 |
echo 'argv.py "$@"' > $script |
55 |
chmod +x $script |
56 |
$SH $script --help --help -h |
57 |
## stdout: ['--help', '--help', '-h'] |
58 |
|
59 |
#### args that look like flags are passed after -c |
60 |
$SH -c 'argv.py "$@"' --help --help -h |
61 |
## stdout: ['--help', '-h'] |
62 |
|
63 |
#### pass short options on command line |
64 |
$SH -e -c 'false; echo status=$?' |
65 |
## stdout-json: "" |
66 |
## status: 1 |
67 |
|
68 |
#### pass long options on command line |
69 |
$SH -o errexit -c 'false; echo status=$?' |
70 |
## stdout-json: "" |
71 |
## status: 1 |
72 |
|
73 |
#### can continue after unknown option |
74 |
# dash and mksh make this a fatal error no matter what. |
75 |
set -o errexit |
76 |
set -o STRICT || true # unknown option |
77 |
echo hello |
78 |
## stdout: hello |
79 |
## status: 0 |
80 |
## BUG dash/mksh stdout-json: "" |
81 |
## BUG dash status: 2 |
82 |
## BUG mksh status: 1 |
83 |
|
84 |
#### set with both options and argv |
85 |
set -o errexit a b c |
86 |
echo "$@" |
87 |
false |
88 |
echo done |
89 |
## stdout: a b c |
90 |
## status: 1 |
91 |
|
92 |
#### set -o vi/emacs |
93 |
set -o vi |
94 |
echo $? |
95 |
set -o emacs |
96 |
echo $? |
97 |
## STDOUT: |
98 |
0 |
99 |
0 |
100 |
## END |
101 |
|
102 |
#### nounset |
103 |
echo "[$unset]" |
104 |
set -o nounset |
105 |
echo "[$unset]" |
106 |
echo end # never reached |
107 |
## stdout: [] |
108 |
## status: 1 |
109 |
## OK dash status: 2 |
110 |
|
111 |
#### -u is nounset |
112 |
echo "[$unset]" |
113 |
set -u |
114 |
echo "[$unset]" |
115 |
echo end # never reached |
116 |
## stdout: [] |
117 |
## status: 1 |
118 |
## OK dash status: 2 |
119 |
|
120 |
#### nounset with "$@" |
121 |
set a b c |
122 |
set -u # shouldn't touch argv |
123 |
echo "$@" |
124 |
## stdout: a b c |
125 |
|
126 |
#### set -u -- clears argv |
127 |
set a b c |
128 |
set -u -- # shouldn't touch argv |
129 |
echo "$@" |
130 |
## stdout: |
131 |
|
132 |
#### set -u -- x y z |
133 |
set a b c |
134 |
set -u -- x y z |
135 |
echo "$@" |
136 |
## stdout: x y z |
137 |
|
138 |
#### reset option with long flag |
139 |
set -o errexit |
140 |
set +o errexit |
141 |
echo "[$unset]" |
142 |
## stdout: [] |
143 |
## status: 0 |
144 |
|
145 |
#### reset option with short flag |
146 |
set -u |
147 |
set +u |
148 |
echo "[$unset]" |
149 |
## stdout: [] |
150 |
## status: 0 |
151 |
|
152 |
#### set -eu (flag parsing) |
153 |
set -eu |
154 |
echo "[$unset]" |
155 |
echo status=$? |
156 |
## stdout-json: "" |
157 |
## status: 1 |
158 |
## OK dash status: 2 |
159 |
|
160 |
#### -n for no execution (useful with --ast-output) |
161 |
# NOTE: set +n doesn't work because nothing is executed! |
162 |
echo 1 |
163 |
set -n |
164 |
echo 2 |
165 |
set +n |
166 |
echo 3 |
167 |
# osh doesn't work because it only checks -n in bin/oil.py? |
168 |
## STDOUT: |
169 |
1 |
170 |
## END |
171 |
## status: 0 |
172 |
|
173 |
#### pipefail |
174 |
# NOTE: the sleeps are because osh can fail non-deterministically because of a |
175 |
# bug. Same problem as PIPESTATUS. |
176 |
{ sleep 0.01; exit 9; } | { sleep 0.02; exit 2; } | { sleep 0.03; exit 0; } |
177 |
echo $? |
178 |
set -o pipefail |
179 |
{ sleep 0.01; exit 9; } | { sleep 0.02; exit 2; } | { sleep 0.03; exit 0; } |
180 |
echo $? |
181 |
## stdout-json: "0\n2\n" |
182 |
## status: 0 |
183 |
## N-I dash stdout-json: "0\n" |
184 |
## N-I dash status: 2 |
185 |
|
186 |
#### shopt -p -o |
187 |
shopt -po nounset |
188 |
set -u |
189 |
shopt -po nounset |
190 |
## stdout-json: "set +o nounset\nset -o nounset\n" |
191 |
## N-I dash/mksh stdout-json: "" |
192 |
## N-I dash/mksh status: 127 |
193 |
|
194 |
#### shopt -p |
195 |
shopt -p nullglob |
196 |
shopt -s nullglob |
197 |
shopt -p nullglob |
198 |
## stdout-json: "shopt -u nullglob\nshopt -s nullglob\n" |
199 |
## N-I dash/mksh stdout-json: "" |
200 |
## N-I dash/mksh status: 127 |
201 |
|
202 |
#### noclobber off |
203 |
set -o errexit |
204 |
echo foo > $TMP/can-clobber |
205 |
set +C |
206 |
echo foo > $TMP/can-clobber |
207 |
set +o noclobber |
208 |
echo foo > $TMP/can-clobber |
209 |
cat $TMP/can-clobber |
210 |
## stdout: foo |
211 |
|
212 |
#### noclobber on |
213 |
# Not implemented yet. |
214 |
rm $TMP/no-clobber |
215 |
set -C |
216 |
echo foo > $TMP/no-clobber |
217 |
echo $? |
218 |
echo foo > $TMP/no-clobber |
219 |
echo $? |
220 |
## stdout-json: "0\n1\n" |
221 |
## OK dash stdout-json: "0\n2\n" |
222 |
|
223 |
#### SHELLOPTS is updated when options are changed |
224 |
echo $SHELLOPTS | grep -q xtrace |
225 |
echo $? |
226 |
set -x |
227 |
echo $SHELLOPTS | grep -q xtrace |
228 |
echo $? |
229 |
set +x |
230 |
echo $SHELLOPTS | grep -q xtrace |
231 |
echo $? |
232 |
## stdout-json: "1\n0\n1\n" |
233 |
## N-I dash/mksh stdout-json: "1\n1\n1\n" |
234 |
|
235 |
#### SHELLOPTS is readonly |
236 |
SHELLOPTS=x |
237 |
echo status=$? |
238 |
## stdout: status=1 |
239 |
## N-I dash/mksh stdout: status=0 |
240 |
|
241 |
# Setting a readonly variable in osh is a hard failure. |
242 |
## OK osh status: 1 |
243 |
## OK osh stdout-json: "" |
244 |
|
245 |
#### set -o lists options |
246 |
# NOTE: osh doesn't use the same format yet. |
247 |
set -o | grep -o noexec |
248 |
## STDOUT: |
249 |
noexec |
250 |
## END |
251 |
|
252 |
#### set without args lists variables |
253 |
__GLOBAL=g |
254 |
f() { |
255 |
local __mylocal=L |
256 |
local __OTHERLOCAL=L |
257 |
__GLOBAL=mutated |
258 |
set | grep '^__' |
259 |
} |
260 |
g() { |
261 |
local __var_in_parent_scope=D |
262 |
f |
263 |
} |
264 |
g |
265 |
## status: 0 |
266 |
## STDOUT: |
267 |
__GLOBAL='mutated' |
268 |
__OTHERLOCAL='L' |
269 |
__mylocal='L' |
270 |
__var_in_parent_scope='D' |
271 |
## END |
272 |
## OK bash STDOUT: |
273 |
__GLOBAL=mutated |
274 |
__OTHERLOCAL=L |
275 |
__mylocal=L |
276 |
__var_in_parent_scope=D |
277 |
## END |
278 |
## OK mksh STDOUT: |
279 |
__GLOBAL=mutated |
280 |
__var_in_parent_scope=D |
281 |
__OTHERLOCAL=L |
282 |
__mylocal=L |
283 |
## END |
284 |
|
285 |
#### 'set' and 'eval' round trip |
286 |
|
287 |
# NOTE: not testing arrays and associative arrays! |
288 |
_space='[ ]' |
289 |
_whitespace=$'[\t\r\n]' |
290 |
_sq="'single quotes'" |
291 |
_backslash_dq="\\ \"" |
292 |
_unicode=$'[\u03bc]' |
293 |
|
294 |
# Save the variables |
295 |
varfile=$TMP/vars-$(basename $SH).txt |
296 |
|
297 |
set | grep '^_' > "$varfile" |
298 |
|
299 |
# Unset variables |
300 |
unset _space _whitespace _sq _backslash_dq _unicode |
301 |
echo [ $_space $_whitespace $_sq $_backslash_dq $_unicode ] |
302 |
|
303 |
# Restore them |
304 |
|
305 |
. $varfile |
306 |
echo "Code saved to $varfile" 1>&2 # for debugging |
307 |
|
308 |
test "$_space" = '[ ]' && echo OK |
309 |
test "$_whitespace" = $'[\t\r\n]' && echo OK |
310 |
test "$_sq" = "'single quotes'" && echo OK |
311 |
test "$_backslash_dq" = "\\ \"" && echo OK |
312 |
test "$_unicode" = $'[\u03bc]' && echo OK |
313 |
|
314 |
## STDOUT: |
315 |
[ ] |
316 |
OK |
317 |
OK |
318 |
OK |
319 |
OK |
320 |
OK |
321 |
## END |
322 |
|
323 |
#### set without args and array variables (not in OSH) |
324 |
declare -a __array |
325 |
__array=(1 2 '3 4') |
326 |
set | grep '^__' |
327 |
## STDOUT: |
328 |
__array=([0]="1" [1]="2" [2]="3 4") |
329 |
## END |
330 |
## OK mksh STDOUT: |
331 |
__array[0]=1 |
332 |
__array[1]=2 |
333 |
__array[2]='3 4' |
334 |
## N-I dash stdout-json: "" |
335 |
## N-I dash status: 2 |
336 |
## N-I osh stdout-json: "" |
337 |
## N-I osh status: 1 |
338 |
|
339 |
#### set without args and assoc array variables (not in OSH) |
340 |
typeset -A __assoc |
341 |
__assoc['k e y']='v a l' |
342 |
__assoc[a]=b |
343 |
set | grep '^__' |
344 |
## STDOUT: |
345 |
__assoc=(["k e y"]="v a l" [a]="b" ) |
346 |
## END |
347 |
## N-I mksh stdout-json: "" |
348 |
## N-I mksh status: 1 |
349 |
## N-I dash stdout-json: "" |
350 |
## N-I dash status: 1 |
351 |
## N-I osh stdout-json: "" |
352 |
## N-I osh status: 1 |
353 |
|
354 |
#### shopt -q |
355 |
shopt -q nullglob |
356 |
echo nullglob=$? |
357 |
|
358 |
# set it |
359 |
shopt -s nullglob |
360 |
|
361 |
shopt -q nullglob |
362 |
echo nullglob=$? |
363 |
|
364 |
shopt -q nullglob failglob |
365 |
echo nullglob,failglob=$? |
366 |
|
367 |
# set it |
368 |
shopt -s failglob |
369 |
shopt -q nullglob failglob |
370 |
echo nullglob,failglob=$? |
371 |
|
372 |
## STDOUT: |
373 |
nullglob=1 |
374 |
nullglob=0 |
375 |
nullglob,failglob=1 |
376 |
nullglob,failglob=0 |
377 |
## END |
378 |
## N-I dash/mksh STDOUT: |
379 |
nullglob=127 |
380 |
nullglob=127 |
381 |
nullglob,failglob=127 |
382 |
nullglob,failglob=127 |
383 |
## END |
384 |
|
385 |
#### shopt -q invalid |
386 |
shopt -q invalidZZ |
387 |
echo invalidZZ=$? |
388 |
## STDOUT: |
389 |
invalidZZ=2 |
390 |
## END |
391 |
## OK bash STDOUT: |
392 |
invalidZZ=1 |
393 |
## END |
394 |
## N-I dash/mksh STDOUT: |
395 |
invalidZZ=127 |
396 |
## END |
397 |
|
398 |
#### sh -i loads rcfile (when combined with -c) |
399 |
$SH -c 'echo 1' |
400 |
cat >$TMP/rcfile <<EOF |
401 |
echo RCFILE |
402 |
EOF |
403 |
$SH --rcfile $TMP/rcfile -i -c 'echo 2' |
404 |
## STDOUT: |
405 |
1 |
406 |
RCFILE |
407 |
2 |
408 |
## END |
409 |
## N-I dash/mksh STDOUT: |
410 |
1 |
411 |
## END |
412 |
## N-I dash status: 2 |
413 |
## N-I mksh status: 1 |