1 | ## oils_failures_allowed: 1
|
2 | ## compare_shells: bash dash mksh
|
3 |
|
4 | #### >& and <& are the same
|
5 |
|
6 | echo one 1>&2
|
7 |
|
8 | echo two 1<&2
|
9 |
|
10 | ## STDERR:
|
11 | one
|
12 | two
|
13 | ## END
|
14 |
|
15 |
|
16 | #### <&
|
17 | # Is there a simpler test case for this?
|
18 | echo foo51 > $TMP/lessamp.txt
|
19 |
|
20 | exec 6< $TMP/lessamp.txt
|
21 | read line <&6
|
22 |
|
23 | echo "[$line]"
|
24 | ## stdout: [foo51]
|
25 |
|
26 | #### 2>&1 with no command
|
27 | ( exit 42 ) # status is reset after this
|
28 | echo status=$?
|
29 | 2>&1
|
30 | echo status=$?
|
31 | ## STDOUT:
|
32 | status=42
|
33 | status=0
|
34 | ## END
|
35 | ## stderr-json: ""
|
36 |
|
37 |
|
38 | #### 2&>1 (is it a redirect or is it like a&>1)
|
39 | 2&>1
|
40 | echo status=$?
|
41 | ## STDOUT:
|
42 | status=127
|
43 | ## END
|
44 | ## OK mksh/dash STDOUT:
|
45 | status=0
|
46 | ## END
|
47 |
|
48 |
|
49 | #### Nonexistent file
|
50 | cat <$TMP/nonexistent.txt
|
51 | echo status=$?
|
52 | ## stdout: status=1
|
53 | ## OK dash stdout: status=2
|
54 |
|
55 | #### Descriptor redirect with spaces
|
56 | # Hm this seems like a failure of lookahead! The second thing should look to a
|
57 | # file-like thing.
|
58 | # I think this is a posix issue.
|
59 | # tag: posix-issue
|
60 | echo one 1>&2
|
61 | echo two 1 >&2
|
62 | echo three 1>& 2
|
63 | ## STDERR:
|
64 | one
|
65 | two 1
|
66 | three
|
67 | ## END
|
68 |
|
69 | #### Filename redirect with spaces
|
70 | # This time 1 *is* a descriptor, not a word. If you add a space between 1 and
|
71 | # >, it doesn't work.
|
72 | echo two 1> $TMP/file-redir1.txt
|
73 | cat $TMP/file-redir1.txt
|
74 | ## stdout: two
|
75 |
|
76 | #### Quoted filename redirect with spaces
|
77 | # POSIX makes node of this
|
78 | echo two \1 > $TMP/file-redir2.txt
|
79 | cat $TMP/file-redir2.txt
|
80 | ## stdout: two 1
|
81 |
|
82 | #### Descriptor redirect with filename
|
83 | # bash/mksh treat this like a filename, not a descriptor.
|
84 | # dash aborts.
|
85 | echo one 1>&$TMP/nonexistent-filename__
|
86 | echo "status=$?"
|
87 | ## stdout: status=1
|
88 | ## BUG bash stdout: status=0
|
89 | ## OK dash stdout-json: ""
|
90 | ## OK dash status: 2
|
91 |
|
92 | #### Redirect echo to stderr, and then redirect all of stdout somewhere.
|
93 | { echo foo52 1>&2; echo 012345789; } > $TMP/block-stdout.txt
|
94 | cat $TMP/block-stdout.txt | wc -c
|
95 | ## stderr: foo52
|
96 | ## stdout: 10
|
97 |
|
98 | #### Named file descriptor
|
99 | exec {myfd}> $TMP/named-fd.txt
|
100 | echo named-fd-contents >& $myfd
|
101 | cat $TMP/named-fd.txt
|
102 | ## stdout: named-fd-contents
|
103 | ## status: 0
|
104 | ## N-I dash/mksh stdout-json: ""
|
105 | ## N-I dash/mksh status: 127
|
106 |
|
107 | #### Double digit fd (20> file)
|
108 | exec 20> "$TMP/double-digit-fd.txt"
|
109 | echo hello20 >&20
|
110 | cat "$TMP/double-digit-fd.txt"
|
111 | ## stdout: hello20
|
112 | ## BUG dash stdout-json: ""
|
113 | ## BUG dash status: 127
|
114 |
|
115 | #### : 9> fdleak (OSH regression)
|
116 | true 9> "$TMP/fd.txt"
|
117 | ( echo world >&9 )
|
118 | cat "$TMP/fd.txt"
|
119 | ## stdout-json: ""
|
120 |
|
121 | #### : 3>&3 (OSH regression)
|
122 |
|
123 | # mksh started being flaky on the continuous build and during release. We
|
124 | # don't care! Related to issue #330.
|
125 | case $SH in (mksh) exit ;; esac
|
126 |
|
127 | : 3>&3
|
128 | echo hello
|
129 | ## stdout: hello
|
130 | ## BUG mksh stdout-json: ""
|
131 | ## BUG mksh status: 0
|
132 |
|
133 | #### : 3>&3-
|
134 | : 3>&3-
|
135 | echo hello
|
136 | ## stdout: hello
|
137 | ## N-I dash/mksh stdout-json: ""
|
138 | ## N-I mksh status: 1
|
139 | ## N-I dash status: 2
|
140 |
|
141 | #### 3>&- << EOF (OSH regression: fail to restore fds)
|
142 | exec 3> "$TMP/fd.txt"
|
143 | echo hello 3>&- << EOF
|
144 | EOF
|
145 | echo world >&3
|
146 | exec 3>&- # close
|
147 | cat "$TMP/fd.txt"
|
148 | ## STDOUT:
|
149 | hello
|
150 | world
|
151 | ## END
|
152 |
|
153 | #### Open file on descriptor 3 and write to it many times
|
154 |
|
155 | # different than case below because 3 is the likely first FD of open()
|
156 |
|
157 | exec 3> "$TMP/fd3.txt"
|
158 | echo hello >&3
|
159 | echo world >&3
|
160 | exec 3>&- # close
|
161 | cat "$TMP/fd3.txt"
|
162 | ## STDOUT:
|
163 | hello
|
164 | world
|
165 | ## END
|
166 |
|
167 | #### Open file on descriptor 4 and write to it many times
|
168 |
|
169 | # different than the case above because because 4 isn't the likely first FD
|
170 |
|
171 | exec 4> "$TMP/fd4.txt"
|
172 | echo hello >&4
|
173 | echo world >&4
|
174 | exec 4>&- # close
|
175 | cat "$TMP/fd4.txt"
|
176 | ## STDOUT:
|
177 | hello
|
178 | world
|
179 | ## END
|
180 |
|
181 | #### Redirect to empty string
|
182 | f=''
|
183 | echo s > "$f"
|
184 | echo "result=$?"
|
185 | set -o errexit
|
186 | echo s > "$f"
|
187 | echo DONE
|
188 | ## stdout: result=1
|
189 | ## status: 1
|
190 | ## OK dash stdout: result=2
|
191 | ## OK dash status: 2
|
192 |
|
193 | #### Redirect to file descriptor that's not open
|
194 | # Notes:
|
195 | # - 7/2021: descriptor 7 seems to work on all CI systems. The process state
|
196 | # isn't clean, but we could probably close it in OSH?
|
197 | # - dash doesn't allow file descriptors greater than 9. (This is a good
|
198 | # thing, because the bash chapter in AOSA book mentions that juggling user
|
199 | # vs. system file descriptors is a huge pain.)
|
200 | # - But somehow running in parallel under spec-runner.sh changes whether
|
201 | # descriptor 3 is open. e.g. 'echo hi 1>&3'. Possibly because of
|
202 | # /usr/bin/time. The _tmp/spec/*.task.txt file gets corrupted!
|
203 | # - Oh this is because I use time --output-file. That opens descriptor 3. And
|
204 | # then time forks the shell script. The file descriptor table is inherited.
|
205 | # - You actually have to set the file descriptor to something. What do
|
206 | # configure and debootstrap too?
|
207 |
|
208 | opened=$(ls /proc/$$/fd)
|
209 | if echo "$opened" | egrep '^7$'; then
|
210 | echo "FD 7 shouldn't be open"
|
211 | echo "OPENED:"
|
212 | echo "$opened"
|
213 | fi
|
214 |
|
215 | echo hi 1>&7
|
216 | ## stdout-json: ""
|
217 | ## status: 1
|
218 | ## OK dash status: 2
|
219 |
|
220 | #### Open descriptor with exec
|
221 | # What is the point of this? ./configure scripts and debootstrap use it.
|
222 | exec 3>&1
|
223 | echo hi 1>&3
|
224 | ## stdout: hi
|
225 | ## status: 0
|
226 |
|
227 | #### Open multiple descriptors with exec
|
228 | # What is the point of this? ./configure scripts and debootstrap use it.
|
229 | exec 3>&1
|
230 | exec 4>&1
|
231 | echo three 1>&3
|
232 | echo four 1>&4
|
233 | ## STDOUT:
|
234 | three
|
235 | four
|
236 | ## END
|
237 | ## status: 0
|
238 |
|
239 | #### >| to clobber
|
240 | echo XX >| $TMP/c.txt
|
241 |
|
242 | set -o noclobber
|
243 |
|
244 | echo YY > $TMP/c.txt # not clobber
|
245 | echo status=$?
|
246 |
|
247 | cat $TMP/c.txt
|
248 | echo ZZ >| $TMP/c.txt
|
249 |
|
250 | cat $TMP/c.txt
|
251 | ## STDOUT:
|
252 | status=1
|
253 | XX
|
254 | ZZ
|
255 | ## END
|
256 | ## OK dash STDOUT:
|
257 | status=2
|
258 | XX
|
259 | ZZ
|
260 | ## END
|
261 |
|
262 | #### &> redirects stdout and stderr
|
263 | tmp="$(basename $SH)-$$.txt" # unique name for shell and test case
|
264 | #echo $tmp
|
265 |
|
266 | stdout_stderr.py &> $tmp
|
267 |
|
268 | # order is indeterminate
|
269 | grep STDOUT $tmp
|
270 | grep STDERR $tmp
|
271 |
|
272 | ## STDOUT:
|
273 | STDOUT
|
274 | STDERR
|
275 | ## END
|
276 | ## N-I dash stdout: STDOUT
|
277 | ## N-I dash stderr: STDERR
|
278 | ## N-I dash status: 1
|
279 |
|
280 | #### >&word redirects stdout and stderr when word is not a number or -
|
281 |
|
282 | # dash, mksh don't implement this bash behaviour.
|
283 | case $SH in (dash|mksh) exit 1 ;; esac
|
284 |
|
285 | tmp="$(basename $SH)-$$.txt" # unique name for shell and test case
|
286 |
|
287 | stdout_stderr.py >&$tmp
|
288 |
|
289 | # order is indeterminate
|
290 | grep STDOUT $tmp
|
291 | grep STDERR $tmp
|
292 |
|
293 | ## STDOUT:
|
294 | STDOUT
|
295 | STDERR
|
296 | ## END
|
297 | ## N-I dash/mksh status: 1
|
298 | ## N-I dash/mksh stdout-json: ""
|
299 |
|
300 | #### 1>&- to close file descriptor
|
301 | exec 5> "$TMP/f.txt"
|
302 | echo hello >&5
|
303 | exec 5>&-
|
304 | echo world >&5
|
305 | cat "$TMP/f.txt"
|
306 | ## STDOUT:
|
307 | hello
|
308 | ## END
|
309 |
|
310 | #### 1>&2- to move file descriptor
|
311 | exec 5> "$TMP/f.txt"
|
312 | echo hello5 >&5
|
313 | exec 6>&5-
|
314 | echo world5 >&5
|
315 | echo world6 >&6
|
316 | exec 6>&-
|
317 | cat "$TMP/f.txt"
|
318 | ## STDOUT:
|
319 | hello5
|
320 | world6
|
321 | ## END
|
322 | ## N-I dash status: 2
|
323 | ## N-I dash stdout-json: ""
|
324 | ## N-I mksh status: 1
|
325 | ## N-I mksh stdout-json: ""
|
326 |
|
327 | #### 1>&2- (Bash bug: fail to restore closed fd)
|
328 |
|
329 | # 7/2021: descriptor 8 is open on Github Actions, so use descriptor 6 instead
|
330 |
|
331 | # Fix for CI systems where process state isn't clean: Close descriptors 6 and 7.
|
332 | exec 6>&- 7>&-
|
333 |
|
334 | opened=$(ls /proc/$$/fd)
|
335 | if echo "$opened" | egrep '^7$'; then
|
336 | echo "FD 7 shouldn't be open"
|
337 | echo "OPENED:"
|
338 | echo "$opened"
|
339 | fi
|
340 | if echo "$opened" | egrep '^6$'; then
|
341 | echo "FD 6 shouldn't be open"
|
342 | echo "OPENED:"
|
343 | echo "$opened"
|
344 | fi
|
345 |
|
346 | exec 7> "$TMP/f.txt"
|
347 | : 6>&7 7>&-
|
348 | echo hello >&7
|
349 | : 6>&7-
|
350 | echo world >&7
|
351 | exec 7>&-
|
352 | cat "$TMP/f.txt"
|
353 |
|
354 | ## status: 1
|
355 | ## stdout-json: ""
|
356 |
|
357 | ## OK dash status: 2
|
358 |
|
359 | ## BUG bash status: 0
|
360 | ## BUG bash stdout: hello
|
361 |
|
362 | #### <> for read/write
|
363 | echo first >$TMP/rw.txt
|
364 | exec 8<>$TMP/rw.txt
|
365 | read line <&8
|
366 | echo line=$line
|
367 | echo second 1>&8
|
368 | echo CONTENTS
|
369 | cat $TMP/rw.txt
|
370 | ## STDOUT:
|
371 | line=first
|
372 | CONTENTS
|
373 | first
|
374 | second
|
375 | ## END
|
376 |
|
377 | #### <> for read/write named pipes
|
378 | rm -f "$TMP/f.pipe"
|
379 | mkfifo "$TMP/f.pipe"
|
380 | exec 8<> "$TMP/f.pipe"
|
381 | echo first >&8
|
382 | echo second >&8
|
383 | read line1 <&8
|
384 | read line2 <&8
|
385 | exec 8<&-
|
386 | echo line1=$line1 line2=$line2
|
387 | ## stdout: line1=first line2=second
|
388 |
|
389 | #### &>> appends stdout and stderr
|
390 |
|
391 | # Fix for flaky tests: dash behaves non-deterministically under load! It
|
392 | # doesn't implement the behavior anyway so I don't care why.
|
393 | case $SH in
|
394 | *dash)
|
395 | exit 1
|
396 | ;;
|
397 | esac
|
398 |
|
399 | echo "ok" > $TMP/f.txt
|
400 | stdout_stderr.py &>> $TMP/f.txt
|
401 | grep ok $TMP/f.txt >/dev/null && echo 'ok'
|
402 | grep STDOUT $TMP/f.txt >/dev/null && echo 'ok'
|
403 | grep STDERR $TMP/f.txt >/dev/null && echo 'ok'
|
404 | ## STDOUT:
|
405 | ok
|
406 | ok
|
407 | ok
|
408 | ## END
|
409 | ## N-I dash stdout-json: ""
|
410 | ## N-I dash status: 1
|
411 |
|
412 | #### exec redirect then various builtins
|
413 | exec 5>$TMP/log.txt
|
414 | echo hi >&5
|
415 | set -o >&5
|
416 | echo done
|
417 | ## STDOUT:
|
418 | done
|
419 | ## END
|
420 |
|
421 | #### can't mention big file descriptor
|
422 | echo hi 9>&1
|
423 | # trivia: 23 is the max descriptor for mksh
|
424 | #echo hi 24>&1
|
425 | echo hi 99>&1
|
426 | echo hi 100>&1
|
427 | ## OK osh STDOUT:
|
428 | hi
|
429 | hi
|
430 | hi 100
|
431 | ## END
|
432 | ## STDOUT:
|
433 | hi
|
434 | hi 99
|
435 | hi 100
|
436 | ## END
|
437 | ## BUG bash STDOUT:
|
438 | hi
|
439 | hi
|
440 | hi
|
441 | ## END
|
442 |
|
443 | #### : >/dev/null 2> / (OSH regression: fail to pop fd frame)
|
444 | # oil 0.8.pre4 fails to restore fds after redirection failure. In the
|
445 | # following case, the fd frame remains after the redirection failure
|
446 | # "2> /" so that the effect of redirection ">/dev/null" remains after
|
447 | # the completion of the command.
|
448 | : >/dev/null 2> /
|
449 | echo hello
|
450 | ## stdout: hello
|
451 | ## OK dash stdout-json: ""
|
452 | ## OK dash status: 2
|
453 | ## OK mksh stdout-json: ""
|
454 | ## OK mksh status: 1
|
455 | # dash/mksh terminates the execution of script on the redirection.
|
456 |
|
457 | #### echo foo >&100 (OSH regression: does not fail with invalid fd 100)
|
458 | # oil 0.8.pre4 does not fail with non-existent fd 100.
|
459 | fd=100
|
460 | echo foo53 >&$fd
|
461 | ## stdout-json: ""
|
462 | ## status: 1
|
463 | ## OK dash status: 2
|
464 |
|
465 | #### echo foo >&N where N is first unused fd
|
466 | # 1. prepare default fd for internal uses
|
467 | minfd=10
|
468 | case ${SH##*/} in
|
469 | (mksh) minfd=24 ;;
|
470 | (osh) minfd=100 ;;
|
471 | esac
|
472 |
|
473 | # 2. prepare first unused fd
|
474 | fd=$minfd
|
475 | is_fd_open() { : >&$1; }
|
476 | while is_fd_open "$fd"; do
|
477 | : $((fd+=1))
|
478 |
|
479 | # OLD: prevent infinite loop for broken oils-for-unix
|
480 | #if test $fd -gt 1000; then
|
481 | # break
|
482 | #fi
|
483 | done
|
484 |
|
485 | # 3. test
|
486 | echo foo54 >&$fd
|
487 | ## stdout-json: ""
|
488 | ## status: 1
|
489 | ## OK dash status: 2
|
490 |
|
491 | #### exec {fd}>&- (OSH regression: fails to close fd)
|
492 | # mksh, dash do not implement {fd} redirections.
|
493 | case $SH in (mksh|dash) exit 1 ;; esac
|
494 | # oil 0.8.pre4 fails to close fd by {fd}&-.
|
495 | exec {fd}>file1
|
496 | echo foo55 >&$fd
|
497 | exec {fd}>&-
|
498 | echo bar >&$fd
|
499 | cat file1
|
500 | ## stdout: foo55
|
501 | ## N-I mksh/dash stdout-json: ""
|
502 | ## N-I mksh/dash status: 1
|