xref: /titanic_50/usr/src/lib/libshell/common/tests/options.sh (revision f38cb554a534c6df738be3f4d23327e69888e634)
1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2010 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                  Common Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#            http://www.opensource.org/licenses/cpl1.0.txt             #
11#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	let Errors+=1
25}
26alias err_exit='err_exit $LINENO'
27
28Command=${0##*/}
29integer Errors=0
30
31unset HISTFILE
32export LC_ALL=C ENV=
33
34ulimit -c 0
35
36tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
37trap "cd /; rm -rf $tmp" EXIT
38
39if	[[ $( ${SHELL-ksh} -s hello<<-\!
40		print $1
41		!
42	 ) != hello ]]
43then	err_exit "${SHELL-ksh} -s not working"
44fi
45x=$(
46	set -e
47	false && print bad
48	print good
49)
50if	[[ $x != good ]]
51then	err_exit 'sh -e not working'
52fi
53[[ $($SHELL -D -c 'print hi; print $"hello"') == '"hello"' ]] || err_exit 'ksh -D not working'
54
55env=$tmp/.env
56print $'(print -u1 aha) &>/dev/null\n(print -u2 aha) &>/dev/null' > $env
57rc=$tmp/.kshrc
58print $'PS1=""\nfunction env_hit\n{\n\tprint OK\n}' > $rc
59
60export ENV=/.$env
61if	[[ ! -o privileged ]]
62then
63	got=$($SHELL -E -c : 2>/dev/null)
64	if	[[ $g ]]
65	then
66		got=$(printf %q "$got")
67		err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got"
68	fi
69	got=$($SHELL -E -c : 2>&1 >/dev/null)
70	if	[[ $got != *nonstandard* || $got == *$'\n'* ]]
71	then
72		got=$(printf %q "$got")
73		err_exit "\$ENV file &>/dev/null does not redirect stderr -- expected one diagnostic line, got $got"
74	fi
75fi
76
77export ENV=/.$rc
78if	[[ -o privileged ]]
79then
80	[[ $(print env_hit | $SHELL 2>&1) == "OK" ]] &&
81		err_exit 'privileged nointeractive shell reads $ENV file'
82	[[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] &&
83		err_exit 'privileged -E reads $ENV file'
84	[[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] &&
85		err_exit 'privileged +E reads $ENV file'
86	[[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] &&
87		err_exit 'privileged --rc reads $ENV file'
88	[[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] &&
89		err_exit 'privileged --norc reads $ENV file'
90else
91	[[ $(print env_hit | $SHELL 2>&1) == "OK" ]] &&
92		err_exit 'nointeractive shell reads $ENV file'
93	[[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] ||
94		err_exit '-E ignores $ENV file'
95	[[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] &&
96		err_exit '+E reads $ENV file'
97	[[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] ||
98		err_exit '--rc ignores $ENV file'
99	[[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] &&
100		err_exit '--norc reads $ENV file'
101	[[ $(print env_hit | $SHELL -i 2>&1) == "OK" ]] ||
102		err_exit '-i ignores $ENV file'
103fi
104
105export ENV=
106if	[[ -o privileged ]]
107then
108	[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
109		err_exit 'privileged nointeractive shell reads $HOME/.kshrc file'
110	[[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] &&
111		err_exit 'privileged -E ignores empty $ENV'
112	[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
113		err_exit 'privileged +E reads $HOME/.kshrc file'
114	[[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] &&
115		err_exit 'privileged --rc ignores empty $ENV'
116	[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
117		err_exit 'privileged --norc reads $HOME/.kshrc file'
118else
119	[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
120		err_exit 'nointeractive shell reads $HOME/.kshrc file'
121	[[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] &&
122		err_exit '-E ignores empty $ENV'
123	[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
124		err_exit '+E reads $HOME/.kshrc file'
125	[[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] &&
126		err_exit '--rc ignores empty $ENV'
127	[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
128		err_exit '--norc reads $HOME/.kshrc file'
129fi
130
131unset ENV
132if	[[ -o privileged ]]
133then
134	[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
135		err_exit 'privileged nointeractive shell reads $HOME/.kshrc file'
136	[[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] &&
137		err_exit 'privileged -E reads $HOME/.kshrc file'
138	[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
139		err_exit 'privileged +E reads $HOME/.kshrc file'
140	[[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] &&
141		err_exit 'privileged --rc reads $HOME/.kshrc file'
142	[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
143		err_exit 'privileged --norc reads $HOME/.kshrc file'
144else
145	[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
146		err_exit 'nointeractive shell reads $HOME/.kshrc file'
147	[[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] ||
148		err_exit '-E ignores $HOME/.kshrc file'
149	[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
150		err_exit '+E reads $HOME/.kshrc file'
151	[[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] ||
152		err_exit '--rc ignores $HOME/.kshrc file'
153	[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
154		err_exit '--norc reads $HOME/.kshrc file'
155fi
156
157rm -rf $tmp/.kshrc
158
159if	command set -G 2> /dev/null
160then	cd $tmp
161	mkdir bar foo
162	> bar.c > bam.c
163	> bar/foo.c > bar/bam.c
164	> foo/bam.c
165	set -- **.c
166	expected='bam.c bar.c'
167	[[ $* == $expected ]] ||
168		err_exit "-G **.c failed -- expected '$expected', got '$*'"
169	set -- **
170	expected='bam.c bar bar.c bar/bam.c bar/foo.c foo foo/bam.c'
171	[[ $* == $expected ]] ||
172		err_exit "-G ** failed -- expected '$expected', got '$*'"
173	set -- **/*.c
174	expected='bam.c bar.c bar/bam.c bar/foo.c foo/bam.c'
175	[[ $* == $expected ]] ||
176		err_exit "-G **/*.c failed -- expected '$expected', got '$*'"
177	set -- **/bam.c
178	expected='bam.c bar/bam.c foo/bam.c'
179	[[ $* == $expected ]] ||
180		err_exit "-G **/bam.c failed -- expected '$expected', got '$*'"
181	cd ~-
182fi
183
184cd $tmp
185t="<$$>.profile.<$$>"
186echo "echo '$t'" > .profile
187cp $SHELL ./-ksh
188if	[[ -o privileged ]]
189then
190	[[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] &&
191		err_exit 'privileged -l reads .profile'
192	[[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] &&
193		err_exit 'privileged --login reads .profile'
194	[[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] &&
195		err_exit 'privileged --login-shell reads .profile'
196	[[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] &&
197		err_exit 'privileged --login_shell reads .profile'
198	[[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] &&
199		err_exit 'privileged exec -a -ksh ksh reads .profile'
200	[[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] &&
201		err_exit 'privileged ./-ksh reads .profile'
202	[[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] &&
203		err_exit 'privileged ./-ksh -p reads .profile'
204else
205	[[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] ||
206		err_exit '-l ignores .profile'
207	[[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] ||
208		err_exit '--login ignores .profile'
209	[[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] ||
210		err_exit '--login-shell ignores .profile'
211	[[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] ||
212		err_exit '--login_shell ignores .profile'
213	[[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] ||
214		err_exit 'exec -a -ksh ksh 2>/dev/null ignores .profile'
215	[[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] ||
216		err_exit 'exec -a -ksh ksh 2>&1 ignores .profile'
217	[[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] ||
218		err_exit './-ksh ignores .profile'
219	[[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] &&
220		err_exit './-ksh -p does not ignore .profile'
221fi
222cd ~-
223rm -rf $tmp/.profile
224
225# { exec interactive login_shell restricted xtrace } in the following test
226
227for opt in \
228	allexport all-export all_export \
229	bgnice bg-nice bg_nice \
230	clobber emacs \
231	errexit err-exit err_exit \
232	glob \
233	globstar glob-star glob_star \
234	gmacs \
235	ignoreeof ignore-eof ignore_eof \
236	keyword log markdirs monitor notify \
237	pipefail pipe-fail pipe_fail \
238	trackall track-all track_all \
239	unset verbose vi \
240	viraw vi-raw vi_raw
241do	old=$opt
242	if [[ ! -o $opt ]]
243	then	old=no$opt
244	fi
245
246	set --$opt || err_exit "set --$opt failed"
247	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
248	[[ -o no$opt ]] && err_exit "[[ -o no$opt ]] failed"
249	[[ -o no-$opt ]] && err_exit "[[ -o no-$opt ]] failed"
250	[[ -o no_$opt ]] && err_exit "[[ -o no_$opt ]] failed"
251	[[ -o ?$opt ]] || err_exit "[[ -o ?$opt ]] failed"
252	[[ -o ?no$opt ]] || err_exit "[[ -o ?no$opt ]] failed"
253	[[ -o ?no-$opt ]] || err_exit "[[ -o ?no-$opt ]] failed"
254	[[ -o ?no_$opt ]] || err_exit "[[ -o ?no_$opt ]] failed"
255
256	set --no$opt || err_exit "set --no$opt failed"
257	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
258	[[ -o $opt ]] && err_exit "[[ -o $opt ]] failed"
259
260	set --no-$opt || err_exit "set --no-$opt failed"
261	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
262	[[ -o $opt ]] && err_exit "[[ -o $opt ]] failed"
263
264	set --no_$opt || err_exit "set --no_$opt failed"
265	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
266	[[ -o $opt ]] && err_exit "[[ -o $opt ]] failed"
267
268	set -o $opt || err_exit "set -o $opt failed"
269	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
270	set -o $opt=1 || err_exit "set -o $opt=1 failed"
271	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
272	set -o no$opt=0 || err_exit "set -o no$opt=0 failed"
273	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
274	set --$opt=1 || err_exit "set --$opt=1 failed"
275	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
276	set --no$opt=0 || err_exit "set --no$opt=0 failed"
277	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
278
279	set -o no$opt || err_exit "set -o no$opt failed"
280	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
281	set -o $opt=0 || err_exit "set -o $opt=0 failed"
282	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
283	set -o no$opt=1 || err_exit "set -o no$opt=1 failed"
284	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
285	set --$opt=0 || err_exit "set --$opt=0 failed"
286	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
287	set --no$opt=1 || err_exit "set --no$opt=1 failed"
288	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
289
290	set -o no-$opt || err_exit "set -o no-$opt failed"
291	[[ -o no-$opt ]] || err_exit "[[ -o no-$opt ]] failed"
292
293	set -o no_$opt || err_exit "set -o no_$opt failed"
294	[[ -o no_$opt ]] || err_exit "[[ -o no_$opt ]] failed"
295
296	set +o $opt || err_exit "set +o $opt failed"
297	[[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed"
298
299	set +o no$opt || err_exit "set +o no$opt failed"
300	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
301
302	set +o no-$opt || err_exit "set +o no-$opt failed"
303	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
304
305	set +o no_$opt || err_exit "set +o no_$opt failed"
306	[[ -o $opt ]] || err_exit "[[ -o $opt ]] failed"
307
308	set --$old
309done
310
311for opt in \
312	exec interactive login_shell login-shell logi privileged \
313	rc restricted xtrace
314do	[[ -o $opt ]]
315	y=$?
316	[[ -o no$opt ]]
317	n=$?
318	case $y$n in
319	10|01)	;;
320	*)	err_exit "[[ -o $opt ]] == [[ -o no$opt ]]" ;;
321	esac
322done
323
324for opt in \
325	foo foo-bar foo_bar
326do	if	[[ -o ?$opt ]]
327	then	err_exit "[[ -o ?$opt ]] should fail"
328	fi
329	if	[[ -o ?no$opt ]]
330	then	err_exit "[[ -o ?no$opt ]] should fail"
331	fi
332done
333
334[[ $(set +o) == $(set --state) ]] || err_exit "set --state different from set +o"
335set -- $(set --state)
336[[ $1 == set && $2 == --default ]] || err_exit "set --state failed -- expected 'set --default *', got '$1 $2 *'"
337shift
338restore=$*
339shift
340off=
341for opt
342do	case $opt in
343	--not*)	opt=${opt/--/--no} ;;
344	--no*)	opt=${opt/--no/--} ;;
345	--*)	opt=${opt/--/--no} ;;
346	esac
347	off="$off $opt"
348done
349set $off
350state=$(set --state)
351default=$(set --default --state)
352[[ $state == $default ]] || err_exit "set --state for default options failed: expected '$default', got '$state'"
353set $restore
354state=$(set --state)
355[[ $state == "set $restore" ]] || err_exit "set --state after restore failed: expected 'set $restore', got '$state'"
356
357typeset -a pipeline
358pipeline=(
359	( nopipefail=0 pipefail=1 command='false|true|true' )
360	( nopipefail=0 pipefail=1 command='true|false|true' )
361	( nopipefail=1 pipefail=1 command='true|true|false' )
362	( nopipefail=1 pipefail=1 command='false|false|false' )
363	( nopipefail=0 pipefail=0 command='true|true|true' )
364	( nopipefail=0 pipefail=0 command='print hi|(sleep 1;/bin/cat)>/dev/null' )
365)
366set --nopipefail
367for ((i = 0; i < ${#pipeline[@]}; i++ ))
368do	eval ${pipeline[i].command}
369	status=$?
370	expected=${pipeline[i].nopipefail}
371	[[ $status == $expected ]] ||
372	err_exit "--nopipefail '${pipeline[i].command}' exit status $status -- expected $expected"
373done
374ftt=0
375set --pipefail
376for ((i = 0; i < ${#pipeline[@]}; i++ ))
377do	eval ${pipeline[i].command}
378	status=$?
379	expected=${pipeline[i].pipefail}
380	if	[[ $status != $expected ]]
381	then	err_exit "--pipefail '${pipeline[i].command}' exit status $status -- expected $expected"
382		(( i == 0 )) && ftt=1
383	fi
384done
385if	(( ! ftt ))
386then	exp=10
387	got=$(for((n=1;n<exp;n++))do $SHELL --pipefail -c '(sleep 0.1;false)|true|true' && break; done; print $n)
388	[[ $got == $exp ]] || err_exit "--pipefail -c '(sleep 0.1;false)|true|true' fails with exit status 0 (after $got/$exp iterations)"
389fi
390
391echo=$(whence -p echo)
392for ((i=0; i < 20; i++))
393do	if	! x=$(true | $echo 123)
394	then	err_exit 'command substitution with wrong exit status with pipefai'
395		break
396	fi
397done
398(
399	set -o pipefail
400	false | true
401	(( $? )) || err_exit 'pipe not failing in subshell with pipefail'
402) | wc >/dev/null
403$SHELL -c 'set -o pipefail; false | $(whence -p true);' && err_exit 'pipefail not returning failure with sh -c'
404exp='1212 or 1221'
405got=$(
406	set --pipefail
407	pipe() { date | cat > /dev/null ;}
408	print $'1\n2' |
409	while	read i
410	do 	if	pipe $tmp
411		then	{ print -n $i; sleep 2; print -n $i; } &
412		fi
413	done
414	wait
415)
416[[ $got == @((12|21)(12|21)) ]] || err_exit "& job delayed by --pipefail, expected '$exp', got '$got'"
417$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-'
418> $tmp/.profile
419for i in i l r s D E a b e f h k n t u v x B C G H
420do	HOME=$tmp ENV= $SHELL -$i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not in \$-"
421	[[ \$- == *$i* ]] || exit 1
422	++EOF++
423done
424letters=ilrabefhknuvxBCGE
425integer j=0
426for i in interactive login restricted allexport notify errexit \
427	noglob trackall keyword noexec nounset verbose xtrace braceexpand \
428	noclobber globstar rc
429do	HOME=$tmp ENV= $SHELL -o $i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}"
430	[[ \$- == *${letters:j:1}* ]] || exit 1
431	++EOF++
432	((j++))
433done
434
435export ENV=
436histfile=$tmp/history
437exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo')
438for var in HISTSIZE HISTFILE
439do	got=$( ( HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 )
440	got=${got##*': '}
441	[[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'"
442	got=$( { HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 )
443	got=${got##*': '}
444	[[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'"
445done
446( unset HISTFILE; $SHELL -ic "HISTFILE=$histfile" 2>/dev/null ) || err_exit "setting HISTFILE when not in environment fails"
447
448# the next tests loop on all combinations of
449#	{ SUB PAR CMD ADD }
450
451SUB=(
452	( BEG='$( '	END=' )'	)
453	( BEG='${ '	END='; }'	)
454)
455PAR=(
456	( BEG='( '	END=' )'	)
457	( BEG='{ '	END='; }'	)
458)
459CMD=(	command-kill	script-kill	)
460ADD=(	''		'; :'		)
461
462cd $tmp
463print $'#!'$SHELL$'\nkill -KILL $$' > command-kill
464print $'kill -KILL $$' > script-kill
465chmod +x command-kill script-kill
466export PATH=.:$PATH
467exp='Killed'
468for ((S=0; S<${#SUB[@]}; S++))
469do	for ((P=0; P<${#PAR[@]}; P++))
470	do	for ((C=0; C<${#CMD[@]}; C++))
471		do	for ((A=0; A<${#ADD[@]}; A++))
472			do	cmd="${SUB[S].BEG}${PAR[P].BEG}${CMD[C]}${PAR[P].END} 2>&1${ADD[A]}${SUB[S].END}"
473				eval got="$cmd"
474				got=${got##*': '}
475				got=${got%%'('*}
476				[[ $got == "$exp" ]] || err_exit "$cmd failed -- got '$got', expected '$exp'"
477			done
478		done
479	done
480done
481
482$SHELL 2> /dev/null -c '{; true ;}' || err_exit 'leading ; causes syntax error in brace group'
483$SHELL 2> /dev/null -c '(; true ;)' || err_exit 'leading ; causes syntax error in parenthesis group'
484
485print 'for ((i = 0; i < ${1:-10000}; i++ )); do printf "%.*c\n" 15 x; done' > pipefail
486chmod +x pipefail
487$SHELL --pipefail -c './pipefail 10000 | sed 1q' >/dev/null 2>&1 &
488tst=$!
489{ sleep 4; kill $tst; } 2>/dev/null &
490spy=$!
491wait $tst 2>/dev/null
492status=$?
493if	[[ $status == 0 || $(kill -l $status) == PIPE ]]
494then    kill $spy 2>/dev/null
495else    err_exit "pipefail pipeline bypasses SIGPIPE and hangs"
496fi
497wait
498
499exit $((Errors))
500