1 |
|
2 |
#### >& |
3 |
echo hi 1>&2 |
4 |
## stderr: hi |
5 |
|
6 |
#### <& |
7 |
# Is there a simpler test case for this? |
8 |
echo foo > $TMP/lessamp.txt |
9 |
exec 6< $TMP/lessamp.txt |
10 |
read line <&6 |
11 |
echo "[$line]" |
12 |
## stdout: [foo] |
13 |
|
14 |
#### Leading redirect |
15 |
echo hello >$TMP/hello.txt # temporary fix |
16 |
<$TMP/hello.txt cat |
17 |
## stdout: hello |
18 |
|
19 |
#### Nonexistent file |
20 |
cat <$TMP/nonexistent.txt |
21 |
echo status=$? |
22 |
## stdout: status=1 |
23 |
## OK dash stdout: status=2 |
24 |
|
25 |
#### Redirect in command sub |
26 |
FOO=$(echo foo 1>&2) |
27 |
echo $FOO |
28 |
## stdout: |
29 |
## stderr: foo |
30 |
|
31 |
#### Redirect in assignment |
32 |
# dash captures stderr to a file here, which seems correct. Bash doesn't and |
33 |
# just lets it go to actual stderr. |
34 |
# For now we agree with dash/mksh, since it involves fewer special cases in the |
35 |
# code. |
36 |
|
37 |
FOO=$(echo foo 1>&2) 2>$TMP/no-command.txt |
38 |
echo FILE= |
39 |
cat $TMP/no-command.txt |
40 |
echo "FOO=$FOO" |
41 |
## STDOUT: |
42 |
FILE= |
43 |
foo |
44 |
FOO= |
45 |
## END |
46 |
## BUG bash STDOUT: |
47 |
FILE= |
48 |
FOO= |
49 |
## END |
50 |
|
51 |
#### Redirect in function body. |
52 |
fun() { echo hi; } 1>&2 |
53 |
fun |
54 |
## stdout-json: "" |
55 |
## stderr-json: "hi\n" |
56 |
|
57 |
#### Bad redirects in function body |
58 |
empty='' |
59 |
fun() { echo hi; } > $empty |
60 |
fun |
61 |
echo status=$? |
62 |
## stdout: status=1 |
63 |
## OK dash stdout: status=2 |
64 |
|
65 |
#### Redirect in function body is evaluated multiple times |
66 |
i=0 |
67 |
fun() { echo "file $i"; } 1> "$TMP/file$((i++))" |
68 |
fun |
69 |
fun |
70 |
echo i=$i |
71 |
echo __ |
72 |
cat $TMP/file0 |
73 |
echo __ |
74 |
cat $TMP/file1 |
75 |
## STDOUT: |
76 |
i=2 |
77 |
__ |
78 |
file 1 |
79 |
__ |
80 |
file 2 |
81 |
## END |
82 |
## N-I dash stdout-json: "" |
83 |
## N-I dash status: 2 |
84 |
|
85 |
#### Redirect in function body AND function call |
86 |
fun() { echo hi; } 1>&2 |
87 |
fun 2>&1 |
88 |
## stdout-json: "hi\n" |
89 |
## stderr-json: "" |
90 |
|
91 |
#### Descriptor redirect with spaces |
92 |
# Hm this seems like a failure of lookahead! The second thing should look to a |
93 |
# file-like thing. |
94 |
# I think this is a posix issue. |
95 |
# tag: posix-issue |
96 |
echo one 1>&2 |
97 |
echo two 1 >&2 |
98 |
echo three 1>& 2 |
99 |
## stderr-json: "one\ntwo 1\nthree\n" |
100 |
|
101 |
#### Filename redirect with spaces |
102 |
# This time 1 *is* a descriptor, not a word. If you add a space between 1 and |
103 |
# >, it doesn't work. |
104 |
echo two 1> $TMP/file-redir1.txt |
105 |
cat $TMP/file-redir1.txt |
106 |
## stdout: two |
107 |
|
108 |
#### Quoted filename redirect with spaces |
109 |
# POSIX makes node of this |
110 |
echo two \1 > $TMP/file-redir2.txt |
111 |
cat $TMP/file-redir2.txt |
112 |
## stdout: two 1 |
113 |
|
114 |
#### Descriptor redirect with filename |
115 |
# bash/mksh treat this like a filename, not a descriptor. |
116 |
# dash aborts. |
117 |
echo one 1>&$TMP/nonexistent-filename__ |
118 |
echo "status=$?" |
119 |
## stdout: status=1 |
120 |
## BUG bash stdout: status=0 |
121 |
## OK dash stdout-json: "" |
122 |
## OK dash status: 2 |
123 |
|
124 |
#### redirect for loop |
125 |
for i in $(seq 3) |
126 |
do |
127 |
echo $i |
128 |
done > $TMP/redirect-for-loop.txt |
129 |
cat $TMP/redirect-for-loop.txt |
130 |
## stdout-json: "1\n2\n3\n" |
131 |
|
132 |
#### redirect subshell |
133 |
( echo foo ) 1>&2 |
134 |
## stderr: foo |
135 |
## stdout-json: "" |
136 |
|
137 |
#### Prefix redirect for loop -- not allowed |
138 |
>$TMP/redirect2.txt for i in $(seq 3) |
139 |
do |
140 |
echo $i |
141 |
done |
142 |
cat $TMP/redirect2.txt |
143 |
## status: 2 |
144 |
## OK mksh status: 1 |
145 |
|
146 |
#### Brace group redirect |
147 |
# Suffix works, but prefix does NOT work. |
148 |
# That comes from '| compound_command redirect_list' in the grammar! |
149 |
{ echo block-redirect; } > $TMP/br.txt |
150 |
cat $TMP/br.txt | wc -c |
151 |
## stdout: 15 |
152 |
|
153 |
#### Redirect echo to stderr, and then redirect all of stdout somewhere. |
154 |
{ echo foo 1>&2; echo 012345789; } > $TMP/block-stdout.txt |
155 |
cat $TMP/block-stdout.txt | wc -c |
156 |
## stderr: foo |
157 |
## stdout: 10 |
158 |
|
159 |
#### Redirect in the middle of two assignments |
160 |
FOO=foo >$TMP/out.txt BAR=bar printenv.py FOO BAR |
161 |
tac $TMP/out.txt |
162 |
## stdout-json: "bar\nfoo\n" |
163 |
|
164 |
#### Redirect in the middle of a command |
165 |
f=$TMP/out |
166 |
echo -n 1 2 '3 ' > $f |
167 |
echo -n 4 5 >> $f '6 ' |
168 |
echo -n 7 >> $f 8 '9 ' |
169 |
echo -n >> $f 1 2 '3 ' |
170 |
echo >> $f -n 4 5 '6 ' |
171 |
cat $f |
172 |
## stdout-json: "1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 " |
173 |
|
174 |
#### Named file descriptor |
175 |
exec {myfd}> $TMP/named-fd.txt |
176 |
echo named-fd-contents >& $myfd |
177 |
cat $TMP/named-fd.txt |
178 |
## stdout: named-fd-contents |
179 |
## status: 0 |
180 |
## N-I dash/mksh stdout-json: "" |
181 |
## N-I dash/mksh status: 127 |
182 |
|
183 |
#### Double digit fd (20> file) |
184 |
exec 20> "$TMP/double-digit-fd.txt" |
185 |
echo hello20 >&20 |
186 |
cat "$TMP/double-digit-fd.txt" |
187 |
## stdout: hello20 |
188 |
## BUG dash stdout-json: "" |
189 |
## BUG dash status: 127 |
190 |
|
191 |
#### : 9> fdleak (OSH regression) |
192 |
true 9> "$TMP/fd.txt" |
193 |
( echo world >&9 ) |
194 |
cat "$TMP/fd.txt" |
195 |
## stdout-json: "" |
196 |
|
197 |
#### : 3>&3 (OSH regression) |
198 |
|
199 |
# mksh started being flaky on the continuous build and during release. We |
200 |
# don't care! Related to issue #330. |
201 |
case $SH in (mksh) exit ;; esac |
202 |
|
203 |
: 3>&3 |
204 |
echo hello |
205 |
## stdout: hello |
206 |
## BUG mksh stdout-json: "" |
207 |
## BUG mksh status: 0 |
208 |
|
209 |
#### : 3>&3- |
210 |
: 3>&3- |
211 |
echo hello |
212 |
## stdout: hello |
213 |
## N-I dash/mksh stdout-json: "" |
214 |
## N-I mksh status: 1 |
215 |
## N-I dash status: 2 |
216 |
|
217 |
#### 3>&- << EOF (OSH regression: fail to restore fds) |
218 |
exec 3> "$TMP/fd.txt" |
219 |
echo hello 3>&- << EOF |
220 |
EOF |
221 |
echo world >&3 |
222 |
exec 3>&- # close |
223 |
cat "$TMP/fd.txt" |
224 |
## STDOUT: |
225 |
hello |
226 |
world |
227 |
## END |
228 |
|
229 |
#### Open file on descriptor 3 and write to it many times |
230 |
|
231 |
# different than case below because 3 is the likely first FD of open() |
232 |
|
233 |
exec 3> "$TMP/fd3.txt" |
234 |
echo hello >&3 |
235 |
echo world >&3 |
236 |
exec 3>&- # close |
237 |
cat "$TMP/fd3.txt" |
238 |
## STDOUT: |
239 |
hello |
240 |
world |
241 |
## END |
242 |
|
243 |
#### Open file on descriptor 4 and write to it many times |
244 |
|
245 |
# different than the case above because because 4 isn't the likely first FD |
246 |
|
247 |
exec 4> "$TMP/fd4.txt" |
248 |
echo hello >&4 |
249 |
echo world >&4 |
250 |
exec 4>&- # close |
251 |
cat "$TMP/fd4.txt" |
252 |
## STDOUT: |
253 |
hello |
254 |
world |
255 |
## END |
256 |
|
257 |
#### Redirect function stdout |
258 |
f() { echo one; echo two; } |
259 |
f > $TMP/redirect-func.txt |
260 |
cat $TMP/redirect-func.txt |
261 |
## stdout-json: "one\ntwo\n" |
262 |
|
263 |
#### Nested function stdout redirect |
264 |
# Shows that a stack is necessary. |
265 |
inner() { |
266 |
echo i1 |
267 |
echo i2 |
268 |
} |
269 |
outer() { |
270 |
echo o1 |
271 |
inner > $TMP/inner.txt |
272 |
echo o2 |
273 |
} |
274 |
outer > $TMP/outer.txt |
275 |
cat $TMP/inner.txt |
276 |
echo -- |
277 |
cat $TMP/outer.txt |
278 |
## stdout-json: "i1\ni2\n--\no1\no2\n" |
279 |
|
280 |
#### Redirect to empty string |
281 |
f='' |
282 |
echo s > "$f" |
283 |
echo "result=$?" |
284 |
set -o errexit |
285 |
echo s > "$f" |
286 |
echo DONE |
287 |
## stdout: result=1 |
288 |
## status: 1 |
289 |
## OK dash stdout: result=2 |
290 |
## OK dash status: 2 |
291 |
|
292 |
#### Redirect to file descriptor that's not open |
293 |
# Notes: |
294 |
# - 7/2021: descriptor 7 seems to work on all CI systems. The process state |
295 |
# isn't clean, but we could probably close it in OSH? |
296 |
# - dash doesn't allow file descriptors greater than 9. (This is a good |
297 |
# thing, because the bash chapter in AOSA book mentions that juggling user |
298 |
# vs. system file descriptors is a huge pain.) |
299 |
# - But somehow running in parallel under spec-runner.sh changes whether |
300 |
# descriptor 3 is open. e.g. 'echo hi 1>&3'. Possibly because of |
301 |
# /usr/bin/time. The _tmp/spec/*.task.txt file gets corrupted! |
302 |
# - Oh this is because I use time --output-file. That opens descriptor 3. And |
303 |
# then time forks the shell script. The file descriptor table is inherited. |
304 |
# - You actually have to set the file descriptor to something. What do |
305 |
# configure and debootstrap too? |
306 |
|
307 |
opened=$(ls /proc/$$/fd) |
308 |
if echo "$opened" | egrep '^7$'; then |
309 |
echo "FD 7 shouldn't be open" |
310 |
echo "OPENED:" |
311 |
echo "$opened" |
312 |
fi |
313 |
|
314 |
echo hi 1>&7 |
315 |
## stdout-json: "" |
316 |
## status: 1 |
317 |
## OK dash status: 2 |
318 |
|
319 |
#### Open descriptor with exec |
320 |
# What is the point of this? ./configure scripts and debootstrap use it. |
321 |
exec 3>&1 |
322 |
echo hi 1>&3 |
323 |
## stdout: hi |
324 |
## status: 0 |
325 |
|
326 |
#### Open multiple descriptors with exec |
327 |
# What is the point of this? ./configure scripts and debootstrap use it. |
328 |
exec 3>&1 |
329 |
exec 4>&1 |
330 |
echo three 1>&3 |
331 |
echo four 1>&4 |
332 |
## stdout-json: "three\nfour\n" |
333 |
## status: 0 |
334 |
|
335 |
#### >| to clobber |
336 |
echo XX >| $TMP/c.txt |
337 |
|
338 |
set -o noclobber |
339 |
|
340 |
echo YY > $TMP/c.txt # not globber |
341 |
echo status=$? |
342 |
|
343 |
cat $TMP/c.txt |
344 |
echo ZZ >| $TMP/c.txt |
345 |
|
346 |
cat $TMP/c.txt |
347 |
## STDOUT: |
348 |
status=1 |
349 |
XX |
350 |
ZZ |
351 |
## END |
352 |
## OK dash STDOUT: |
353 |
status=2 |
354 |
XX |
355 |
ZZ |
356 |
## END |
357 |
|
358 |
#### &> redirects stdout and stderr |
359 |
tmp="$(basename $SH)-$$.txt" # unique name for shell and test case |
360 |
#echo $tmp |
361 |
|
362 |
stdout_stderr.py &> $tmp |
363 |
|
364 |
# order is indeterminate |
365 |
grep STDOUT $tmp |
366 |
grep STDERR $tmp |
367 |
|
368 |
## STDOUT: |
369 |
STDOUT |
370 |
STDERR |
371 |
## END |
372 |
## N-I dash stdout: STDOUT |
373 |
## N-I dash stderr: STDERR |
374 |
## N-I dash status: 1 |
375 |
|
376 |
#### >&word redirects stdout and stderr when word is not a number or - |
377 |
|
378 |
# dash, mksh don't implement this bash behaviour. |
379 |
case $SH in (dash|mksh) exit 1 ;; esac |
380 |
|
381 |
tmp="$(basename $SH)-$$.txt" # unique name for shell and test case |
382 |
|
383 |
stdout_stderr.py >&$tmp |
384 |
|
385 |
# order is indeterminate |
386 |
grep STDOUT $tmp |
387 |
grep STDERR $tmp |
388 |
|
389 |
## STDOUT: |
390 |
STDOUT |
391 |
STDERR |
392 |
## END |
393 |
## N-I dash/mksh status: 1 |
394 |
## N-I dash/mksh stdout-json: "" |
395 |
|
396 |
#### 1>&- to close file descriptor |
397 |
exec 5> "$TMP/f.txt" |
398 |
echo hello >&5 |
399 |
exec 5>&- |
400 |
echo world >&5 |
401 |
cat "$TMP/f.txt" |
402 |
## stdout-json: "hello\n" |
403 |
|
404 |
#### 1>&2- to move file descriptor |
405 |
exec 5> "$TMP/f.txt" |
406 |
echo hello5 >&5 |
407 |
exec 6>&5- |
408 |
echo world5 >&5 |
409 |
echo world6 >&6 |
410 |
exec 6>&- |
411 |
cat "$TMP/f.txt" |
412 |
## stdout-json: "hello5\nworld6\n" |
413 |
## N-I dash status: 2 |
414 |
## N-I dash stdout-json: "" |
415 |
## N-I mksh status: 1 |
416 |
## N-I mksh stdout-json: "" |
417 |
|
418 |
#### 1>&2- (Bash bug: fail to restore closed fd) |
419 |
|
420 |
# 7/2021: descriptor 8 is open on Github Actions, so use descriptor 6 instead |
421 |
|
422 |
# Fix for CI systems where process state isn't clean: Close descriptors 6 and 7. |
423 |
exec 6>&- 7>&- |
424 |
|
425 |
opened=$(ls /proc/$$/fd) |
426 |
if echo "$opened" | egrep '^7$'; then |
427 |
echo "FD 7 shouldn't be open" |
428 |
echo "OPENED:" |
429 |
echo "$opened" |
430 |
fi |
431 |
if echo "$opened" | egrep '^6$'; then |
432 |
echo "FD 6 shouldn't be open" |
433 |
echo "OPENED:" |
434 |
echo "$opened" |
435 |
fi |
436 |
|
437 |
exec 7> "$TMP/f.txt" |
438 |
: 6>&7 7>&- |
439 |
echo hello >&7 |
440 |
: 6>&7- |
441 |
echo world >&7 |
442 |
exec 7>&- |
443 |
cat "$TMP/f.txt" |
444 |
## status: 2 |
445 |
## stdout-json: "" |
446 |
## OK mksh status: 1 |
447 |
## BUG bash status: 0 |
448 |
## BUG bash stdout: hello |
449 |
|
450 |
#### <> for read/write |
451 |
echo first >$TMP/rw.txt |
452 |
exec 8<>$TMP/rw.txt |
453 |
read line <&8 |
454 |
echo line=$line |
455 |
echo second 1>&8 |
456 |
echo CONTENTS |
457 |
cat $TMP/rw.txt |
458 |
## stdout-json: "line=first\nCONTENTS\nfirst\nsecond\n" |
459 |
|
460 |
#### <> for read/write named pipes |
461 |
rm -f "$TMP/f.pipe" |
462 |
mkfifo "$TMP/f.pipe" |
463 |
exec 8<> "$TMP/f.pipe" |
464 |
echo first >&8 |
465 |
echo second >&8 |
466 |
read line1 <&8 |
467 |
read line2 <&8 |
468 |
exec 8<&- |
469 |
echo line1=$line1 line2=$line2 |
470 |
## stdout: line1=first line2=second |
471 |
|
472 |
#### &>> appends stdout and stderr |
473 |
|
474 |
# Fix for flaky tests: dash behaves non-deterministically under load! It |
475 |
# doesn't implement the behavior anyway so I don't care why. |
476 |
case $SH in |
477 |
*dash) |
478 |
exit 1 |
479 |
;; |
480 |
esac |
481 |
|
482 |
echo "ok" > $TMP/f.txt |
483 |
stdout_stderr.py &>> $TMP/f.txt |
484 |
grep ok $TMP/f.txt >/dev/null && echo 'ok' |
485 |
grep STDOUT $TMP/f.txt >/dev/null && echo 'ok' |
486 |
grep STDERR $TMP/f.txt >/dev/null && echo 'ok' |
487 |
## STDOUT: |
488 |
ok |
489 |
ok |
490 |
ok |
491 |
## END |
492 |
## N-I dash stdout-json: "" |
493 |
## N-I dash status: 1 |
494 |
|
495 |
#### exec redirect then various builtins |
496 |
exec 5>$TMP/log.txt |
497 |
echo hi >&5 |
498 |
set -o >&5 |
499 |
echo done |
500 |
## STDOUT: |
501 |
done |
502 |
## END |
503 |
|
504 |
#### >$file touches a file |
505 |
rm -f myfile |
506 |
test -f myfile |
507 |
echo status=$? |
508 |
>myfile |
509 |
test -f myfile |
510 |
echo status=$? |
511 |
## STDOUT: |
512 |
status=1 |
513 |
status=0 |
514 |
## END |
515 |
# regression for OSH |
516 |
## stderr-json: "" |
517 |
|
518 |
#### $(< $file) yields the contents of the file |
519 |
|
520 |
echo FOO > myfile |
521 |
foo=$(< myfile) |
522 |
echo $foo |
523 |
## STDOUT: |
524 |
FOO |
525 |
## END |
526 |
## N-I dash/ash/yash stdout-json: "\n" |
527 |
|
528 |
#### $(< file) with more statements |
529 |
|
530 |
# note that it doesn't do this without a command sub! |
531 |
# It's apparently a special case in bash, mksh, and zsh? |
532 |
foo=$(echo begin; < myfile) |
533 |
echo $foo |
534 |
echo --- |
535 |
|
536 |
foo=$(< myfile; echo end) |
537 |
echo $foo |
538 |
echo --- |
539 |
|
540 |
foo=$(< myfile; <myfile) |
541 |
echo $foo |
542 |
echo --- |
543 |
|
544 |
## STDOUT: |
545 |
begin |
546 |
--- |
547 |
end |
548 |
--- |
549 |
|
550 |
--- |
551 |
## END |
552 |
# weird, zsh behaves differently |
553 |
## OK zsh STDOUT: |
554 |
begin |
555 |
FOO |
556 |
--- |
557 |
FOO |
558 |
end |
559 |
--- |
560 |
FOO |
561 |
FOO |
562 |
--- |
563 |
## END |
564 |
|
565 |
|
566 |
#### < file in pipeline and subshell doesn't work |
567 |
echo FOO > file2 |
568 |
|
569 |
# This only happens in command subs, which is weird |
570 |
< file2 | tr A-Z a-z |
571 |
( < file2 ) |
572 |
echo end |
573 |
## STDOUT: |
574 |
end |
575 |
## END |
576 |
|
577 |
#### 2>&1 with no command |
578 |
( exit 42 ) # status is reset after this |
579 |
echo status=$? |
580 |
2>&1 |
581 |
echo status=$? |
582 |
## STDOUT: |
583 |
status=42 |
584 |
status=0 |
585 |
## END |
586 |
## stderr-json: "" |
587 |
|
588 |
#### 2&>1 (is it a redirect or is it like a&>1) |
589 |
2&>1 |
590 |
echo status=$? |
591 |
## STDOUT: |
592 |
status=127 |
593 |
## END |
594 |
## OK mksh/dash STDOUT: |
595 |
status=0 |
596 |
## END |
597 |
|
598 |
#### can't mention big file descriptor |
599 |
echo hi 9>&1 |
600 |
# 23 is the max descriptor fo rmksh |
601 |
#echo hi 24>&1 |
602 |
echo hi 99>&1 |
603 |
echo hi 100>&1 |
604 |
## OK osh STDOUT: |
605 |
hi |
606 |
hi |
607 |
hi 100 |
608 |
## END |
609 |
## STDOUT: |
610 |
hi |
611 |
hi 99 |
612 |
hi 100 |
613 |
## END |
614 |
## BUG bash STDOUT: |
615 |
hi |
616 |
hi |
617 |
hi |
618 |
## END |
619 |
|
620 |
#### : >/dev/null 2> / (OSH regression: fail to pop fd frame) |
621 |
# oil 0.8.pre4 fails to restore fds after redirection failure. In the |
622 |
# following case, the fd frame remains after the redirection failure |
623 |
# "2> /" so that the effect of redirection ">/dev/null" remains after |
624 |
# the completion of the command. |
625 |
: >/dev/null 2> / |
626 |
echo hello |
627 |
## stdout: hello |
628 |
## OK dash stdout-json: "" |
629 |
## OK dash status: 2 |
630 |
## OK mksh stdout-json: "" |
631 |
## OK mksh status: 1 |
632 |
# dash/mksh terminates the execution of script on the redirection. |
633 |
|
634 |
#### echo foo >&100 (OSH regression: does not fail with invalid fd 100) |
635 |
# oil 0.8.pre4 does not fail with non-existent fd 100. |
636 |
fd=100 |
637 |
echo foo >&$fd |
638 |
## stdout-json: "" |
639 |
## status: 1 |
640 |
## OK dash status: 2 |
641 |
|
642 |
#### echo foo >&N where N is first unused fd |
643 |
# 1. prepare default fd for internal uses |
644 |
minfd=10 |
645 |
case ${SH##*/} in |
646 |
(mksh) minfd=24 ;; |
647 |
(osh) minfd=100 ;; |
648 |
esac |
649 |
|
650 |
# 2. prepare first unused fd |
651 |
fd=$minfd |
652 |
is-fd-open() { : >&$1; } |
653 |
while is-fd-open "$fd"; do |
654 |
: $((fd+=1)) |
655 |
|
656 |
# prevent infinite loop for broken oils-for-unix |
657 |
if test $fd -gt 1000; then |
658 |
break |
659 |
fi |
660 |
done |
661 |
|
662 |
# 3. test |
663 |
echo foo >&$fd |
664 |
## stdout-json: "" |
665 |
## status: 1 |
666 |
## OK dash status: 2 |
667 |
|
668 |
#### exec {fd}>&- (OSH regression: fails to close fd) |
669 |
# mksh, dash do not implement {fd} redirections. |
670 |
case $SH in (mksh|dash) exit 1 ;; esac |
671 |
# oil 0.8.pre4 fails to close fd by {fd}&-. |
672 |
exec {fd}>file1 |
673 |
echo foo >&$fd |
674 |
exec {fd}>&- |
675 |
echo bar >&$fd |
676 |
cat file1 |
677 |
## stdout: foo |
678 |
## N-I mksh/dash stdout-json: "" |
679 |
## N-I mksh/dash status: 1 |