1 ## oils_failures_allowed: 2
2 ## compare_shells: bash mksh zsh ash
3
4 #### read line from here doc
5
6 # NOTE: there are TABS below
7 read x <<EOF
8 A B C D E
9 FG
10 EOF
11 echo "[$x]"
12 ## stdout: [A B C D E]
13 ## status: 0
14
15 #### read from empty file
16 echo -n '' > $TMP/empty.txt
17 read x < $TMP/empty.txt
18 argv.py "status=$?" "$x"
19
20 # No variable name, behaves the same
21 read < $TMP/empty.txt
22 argv.py "status=$?" "$REPLY"
23
24 ## STDOUT:
25 ['status=1', '']
26 ['status=1', '']
27 ## END
28 ## OK dash STDOUT:
29 ['status=1', '']
30 ['status=2', '']
31 ## END
32 ## status: 0
33
34 #### read /dev/null
35 read -n 1 </dev/null
36 echo $?
37 ## STDOUT:
38 1
39 ## END
40 ## OK dash stdout: 2
41
42 #### read with zero args
43 echo | read
44 echo status=$?
45 ## STDOUT:
46 status=0
47 ## END
48 ## BUG dash STDOUT:
49 status=2
50 ## END
51
52 #### read builtin with no newline returns status 1
53
54 # This is odd because the variable is populated successfully. OSH/YSH might
55 # need a separate put reading feature that doesn't use IFS.
56
57 echo -n ZZZ | { read x; echo status=$?; echo $x; }
58
59 ## STDOUT:
60 status=1
61 ZZZ
62 ## END
63 ## status: 0
64
65 #### read builtin splits value across multiple vars
66 # NOTE: there are TABS below
67 read x y z <<EOF
68 A B C D E
69 FG
70 EOF
71 echo "[$x/$y/$z]"
72 ## stdout: [A/B/C D E]
73 ## status: 0
74
75 #### read builtin with too few variables
76 set -o errexit
77 set -o nounset # hm this doesn't change it
78 read x y z <<EOF
79 A B
80 EOF
81 echo /$x/$y/$z/
82 ## stdout: /A/B//
83 ## status: 0
84
85 #### read -n (with $REPLY)
86 echo 12345 > $TMP/readn.txt
87 read -n 4 x < $TMP/readn.txt
88 read -n 2 < $TMP/readn.txt # Do it again with no variable
89 argv.py $x $REPLY
90 ## stdout: ['1234', '12']
91 ## N-I dash/zsh stdout: []
92
93 #### IFS= read -n (OSH regression: value saved in tempenv)
94 echo XYZ > "$TMP/readn.txt"
95 IFS= TMOUT= read -n 1 char < "$TMP/readn.txt"
96 argv.py "$char"
97 ## stdout: ['X']
98 ## N-I dash/zsh stdout: ['']
99
100 #### read -n doesn't strip whitespace (bug fix)
101 case $SH in dash|zsh) exit ;; esac
102
103 echo ' a b ' | (read -n 4; echo "[$REPLY]")
104 echo ' a b ' | (read -n 5; echo "[$REPLY]")
105 echo ' a b ' | (read -n 6; echo "[$REPLY]")
106 echo
107
108 echo 'one var strips whitespace'
109 echo ' a b ' | (read -n 4 myvar; echo "[$myvar]")
110 echo ' a b ' | (read -n 5 myvar; echo "[$myvar]")
111 echo ' a b ' | (read -n 6 myvar; echo "[$myvar]")
112 echo
113
114 echo 'three vars'
115 echo ' a b ' | (read -n 4 x y z; echo "[$x] [$y] [$z]")
116 echo ' a b ' | (read -n 5 x y z; echo "[$x] [$y] [$z]")
117 echo ' a b ' | (read -n 6 x y z; echo "[$x] [$y] [$z]")
118
119 ## STDOUT:
120 [ a ]
121 [ a b]
122 [ a b ]
123
124 one var strips whitespace
125 [a]
126 [a b]
127 [a b]
128
129 three vars
130 [a] [] []
131 [a] [b] []
132 [a] [b] []
133 ## END
134
135 ## N-I dash/zsh STDOUT:
136 ## END
137
138 ## BUG mksh STDOUT:
139 [a]
140 [a b]
141 [a b]
142
143 one var strips whitespace
144 [a]
145 [a b]
146 [a b]
147
148 three vars
149 [a] [] []
150 [a] [b] []
151 [a] [b] []
152 ## END
153
154 #### read -d -n - respects delimiter and splits
155
156 case $SH in dash|zsh|ash) exit ;; esac
157
158 echo 'delim c'
159 echo ' a b c ' | (read -d 'c' -n 3; echo "[$REPLY]")
160 echo ' a b c ' | (read -d 'c' -n 4; echo "[$REPLY]")
161 echo ' a b c ' | (read -d 'c' -n 5; echo "[$REPLY]")
162 echo
163
164 echo 'one var'
165 echo ' a b c ' | (read -d 'c' -n 3 myvar; echo "[$myvar]")
166 echo ' a b c ' | (read -d 'c' -n 4 myvar; echo "[$myvar]")
167 echo ' a b c ' | (read -d 'c' -n 5 myvar; echo "[$myvar]")
168 echo
169
170 echo 'three vars'
171 echo ' a b c ' | (read -d 'c' -n 3 x y z; echo "[$x] [$y] [$z]")
172 echo ' a b c ' | (read -d 'c' -n 4 x y z; echo "[$x] [$y] [$z]")
173 echo ' a b c ' | (read -d 'c' -n 5 x y z; echo "[$x] [$y] [$z]")
174
175 ## STDOUT:
176 delim c
177 [ a]
178 [ a ]
179 [ a b]
180
181 one var
182 [a]
183 [a]
184 [a b]
185
186 three vars
187 [a] [] []
188 [a] [] []
189 [a] [b] []
190 ## END
191
192 ## N-I dash/zsh/ash STDOUT:
193 ## END
194
195 ## BUG mksh STDOUT:
196 delim c
197 [a]
198 [a]
199 [a b]
200
201 one var
202 [a]
203 [a]
204 [a b]
205
206 three vars
207 [a] [] []
208 [a] [] []
209 [a] [b] []
210 ## END
211
212
213 #### read -n with invalid arg
214 read -n not_a_number
215 echo status=$?
216 ## stdout: status=2
217 ## OK bash stdout: status=1
218 ## N-I zsh stdout-json: ""
219
220 #### read -n from pipe
221 case $SH in (dash|ash|zsh) exit ;; esac
222
223 echo abcxyz | { read -n 3; echo reply=$REPLY; }
224 ## status: 0
225 ## stdout: reply=abc
226 ## N-I dash/ash stdout-json: ""
227
228 # zsh appears to hang with -k
229 ## N-I zsh stdout-json: ""
230
231 #### read without args uses $REPLY, no splitting occurs (without -n)
232
233 # mksh and zsh implement splitting with $REPLY, bash/ash don't
234
235 echo ' a b ' | (read; echo "[$REPLY]")
236 echo ' a b ' | (read myvar; echo "[$myvar]")
237
238 echo ' a b \
239 line2' | (read; echo "[$REPLY]")
240 echo ' a b \
241 line2' | (read myvar; echo "[$myvar]")
242
243 # Now test with -r
244 echo ' a b \
245 line2' | (read -r; echo "[$REPLY]")
246 echo ' a b \
247 line2' | (read -r myvar; echo "[$myvar]")
248
249 ## STDOUT:
250 [ a b ]
251 [a b]
252 [ a b line2]
253 [a b line2]
254 [ a b \]
255 [a b \]
256 ## END
257 ## BUG mksh/zsh STDOUT:
258 [a b]
259 [a b]
260 [a b line2]
261 [a b line2]
262 [a b \]
263 [a b \]
264 ## END
265 ## BUG dash STDOUT:
266 []
267 [a b ]
268 []
269 [a b line2]
270 []
271 [a b \]
272 ## END
273
274 #### read -n vs. -N
275 # dash, ash and zsh do not implement read -N
276 # mksh treats -N exactly the same as -n
277 case $SH in (dash|ash|zsh) exit ;; esac
278
279 # bash docs: https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
280
281 echo 'a b c' > $TMP/readn.txt
282
283 echo 'read -n'
284 read -n 5 A B C < $TMP/readn.txt; echo "'$A' '$B' '$C'"
285 read -n 4 A B C < $TMP/readn.txt; echo "'$A' '$B' '$C'"
286 echo
287
288 echo 'read -N'
289 read -N 5 A B C < $TMP/readn.txt; echo "'$A' '$B' '$C'"
290 read -N 4 A B C < $TMP/readn.txt; echo "'$A' '$B' '$C'"
291 ## STDOUT:
292 read -n
293 'a' 'b' 'c'
294 'a' 'b' ''
295
296 read -N
297 'a b c' '' ''
298 'a b ' '' ''
299 ## END
300 ## N-I dash/ash/zsh stdout-json: ""
301 ## BUG mksh STDOUT:
302 read -n
303 'a' 'b' 'c'
304 'a' 'b' ''
305
306 read -N
307 'a' 'b' 'c'
308 'a' 'b' ''
309 ## END
310
311 #### read -N ignores delimiters
312 case $SH in (dash|ash|zsh) exit ;; esac
313
314 echo $'a\nb\nc' > $TMP/read-lines.txt
315
316 read -N 3 out < $TMP/read-lines.txt
317 echo "$out"
318 ## STDOUT:
319 a
320 b
321 ## END
322 ## N-I dash/ash/zsh stdout-json: ""
323
324 #### read will unset extranous vars
325
326 echo 'a b' > $TMP/read-few.txt
327
328 c='some value'
329 read a b c < $TMP/read-few.txt
330 echo "'$a' '$b' '$c'"
331
332 case $SH in (dash) exit ;; esac # dash does not implement -n
333
334 c='some value'
335 read -n 3 a b c < $TMP/read-few.txt
336 echo "'$a' '$b' '$c'"
337 ## STDOUT:
338 'a' 'b' ''
339 'a' 'b' ''
340 ## END
341 ## N-I dash STDOUT:
342 'a' 'b' ''
343 ## END
344 ## BUG zsh STDOUT:
345 'a' 'b' ''
346 'b' '' ''
347 ## END
348
349 #### read -r ignores backslashes
350 echo 'one\ two' > $TMP/readr.txt
351 read escaped < $TMP/readr.txt
352 read -r raw < $TMP/readr.txt
353 argv.py "$escaped" "$raw"
354 ## stdout: ['one two', 'one\\ two']
355
356 #### read -r with other backslash escapes
357 echo 'one\ two\x65three' > $TMP/readr.txt
358 read escaped < $TMP/readr.txt
359 read -r raw < $TMP/readr.txt
360 argv.py "$escaped" "$raw"
361 # mksh respects the hex escapes here, but other shells don't!
362 ## stdout: ['one twox65three', 'one\\ two\\x65three']
363 ## BUG mksh/zsh stdout: ['one twoethree', 'one\\ twoethree']
364
365 #### read with line continuation reads multiple physical lines
366 # NOTE: osh failing because of file descriptor issue. stdin has to be closed!
367 tmp=$TMP/$(basename $SH)-readr.txt
368 echo -e 'one\\\ntwo\n' > $tmp
369 read escaped < $tmp
370 read -r raw < $tmp
371 argv.py "$escaped" "$raw"
372 ## stdout: ['onetwo', 'one\\']
373 ## N-I dash stdout: ['-e onetwo', '-e one\\']
374
375 #### read multiple vars spanning many lines
376 read x y << 'EOF'
377 one-\
378 two three-\
379 four five-\
380 six
381 EOF
382 argv.py "$x" "$y" "$z"
383 ## stdout: ['one-two', 'three-four five-six', '']
384
385 #### read -r with \n
386 echo '\nline' > $TMP/readr.txt
387 read escaped < $TMP/readr.txt
388 read -r raw < $TMP/readr.txt
389 argv.py "$escaped" "$raw"
390 # dash/mksh/zsh are bugs because at least the raw mode should let you read a
391 # literal \n.
392 ## stdout: ['nline', '\\nline']
393 ## BUG dash/mksh/zsh stdout: ['', '']
394
395 #### read -s from pipe, not a terminal
396 case $SH in (dash|zsh) exit ;; esac
397
398 # It's hard to really test this because it requires a terminal. We hit a
399 # different code path when reading through a pipe. There can be bugs there
400 # too!
401
402 echo foo | { read -s; echo $REPLY; }
403 echo bar | { read -n 2 -s; echo $REPLY; }
404
405 # Hm no exit 1 here? Weird
406 echo b | { read -n 2 -s; echo $?; echo $REPLY; }
407 ## STDOUT:
408 foo
409 ba
410 0
411 b
412 ## END
413 ## N-I dash/zsh stdout-json: ""
414
415 #### read with IFS=$'\n'
416 # The leading spaces are stripped if they appear in IFS.
417 IFS=$(echo -e '\n')
418 read var <<EOF
419 a b c
420 d e f
421 EOF
422 echo "[$var]"
423 ## stdout: [ a b c]
424 ## N-I dash stdout: [a b c]
425
426 #### read multiple lines with IFS=:
427 # The leading spaces are stripped if they appear in IFS.
428 # IFS chars are escaped with :.
429 tmp=$TMP/$(basename $SH)-read-ifs.txt
430 IFS=:
431 cat >$tmp <<'EOF'
432 \\a :b\: c:d\
433 e
434 EOF
435 read a b c d < $tmp
436 # Use printf because echo in dash/mksh interprets escapes, while it doesn't in
437 # bash.
438 printf "%s\n" "[$a|$b|$c|$d]"
439 ## stdout: [ \a |b: c|d e|]
440
441 #### read with IFS=''
442 IFS=''
443 read x y <<EOF
444 a b c d
445 EOF
446 echo "[$x|$y]"
447 ## stdout: [ a b c d|]
448
449 #### read does not respect C backslash escapes
450
451 # bash doesn't respect these, but other shells do. Gah! I think bash
452 # behavior makes more sense. It only escapes IFS.
453 echo '\a \b \c \d \e \f \g \h \x65 \145 \i' > $TMP/read-c.txt
454 read line < $TMP/read-c.txt
455 echo $line
456 ## stdout-json: "a b c d e f g h x65 145 i\n"
457 ## BUG ash stdout-json: "abcdefghx65 145 i\n"
458 ## BUG dash/zsh stdout-json: "\u0007 \u0008\n"
459 ## BUG mksh stdout-json: "\u0007 \u0008 d \u001b \u000c g h e 145 i\n"
460
461 #### dynamic scope used to set vars
462 f() {
463 read head << EOF
464 ref: refs/heads/dev/andy
465 EOF
466 }
467 f
468 echo $head
469 ## STDOUT:
470 ref: refs/heads/dev/andy
471 ## END
472
473 #### read -a reads into array
474
475 # read -a is used in bash-completion
476 # none of these shells implement it
477 case $SH in
478 *mksh|*dash|*zsh|*/ash)
479 exit 2;
480 ;;
481 esac
482
483 read -a myarray <<'EOF'
484 a b c\ d
485 EOF
486 argv.py "${myarray[@]}"
487
488 # arguments are ignored here
489 read -r -a array2 extra arguments <<'EOF'
490 a b c\ d
491 EOF
492 argv.py "${array2[@]}"
493 argv.py "${extra[@]}"
494 argv.py "${arguments[@]}"
495 ## status: 0
496 ## STDOUT:
497 ['a', 'b', 'c d']
498 ['a', 'b', 'c\\', 'd']
499 []
500 []
501 ## END
502 ## N-I dash/mksh/zsh/ash status: 2
503 ## N-I dash/mksh/zsh/ash stdout-json: ""
504
505 #### read -d : (colon-separated records)
506 printf a,b,c:d,e,f:g,h,i | {
507 IFS=,
508 read -d : v1
509 echo "v1=$v1"
510 read -d : v1 v2
511 echo "v1=$v1 v2=$v2"
512 read -d : v1 v2 v3
513 echo "v1=$v1 v2=$v2 v3=$v3"
514 }
515 ## STDOUT:
516 v1=a,b,c
517 v1=d v2=e,f
518 v1=g v2=h v3=i
519 ## END
520 ## N-I dash STDOUT:
521 v1=
522 v1= v2=
523 v1= v2= v3=
524 ## END
525
526 #### read -d '' (null-separated records)
527 printf 'a,b,c\0d,e,f\0g,h,i' | {
528 IFS=,
529 read -d '' v1
530 echo "v1=$v1"
531 read -d '' v1 v2
532 echo "v1=$v1 v2=$v2"
533 read -d '' v1 v2 v3
534 echo "v1=$v1 v2=$v2 v3=$v3"
535 }
536 ## STDOUT:
537 v1=a,b,c
538 v1=d v2=e,f
539 v1=g v2=h v3=i
540 ## END
541 ## N-I dash STDOUT:
542 v1=
543 v1= v2=
544 v1= v2= v3=
545 ## END
546
547 #### read -rd
548 read -rd '' var <<EOF
549 foo
550 bar
551 EOF
552 echo "$var"
553 ## STDOUT:
554 foo
555 bar
556 ## END
557 ## N-I dash stdout-json: "\n"
558
559 #### read -d when there's no delimiter
560 { read -d : part
561 echo $part $?
562 read -d : part
563 echo $part $?
564 } <<EOF
565 foo:bar
566 EOF
567 ## STDOUT:
568 foo 0
569 bar 1
570 ## END
571 ## N-I dash STDOUT:
572 2
573 2
574 ## END
575
576 #### read -t 0 tests if input is available
577 case $SH in (dash|zsh|mksh) exit ;; esac
578
579 # is there input available?
580 read -t 0 < /dev/null
581 echo $?
582
583 # floating point
584 read -t 0.0 < /dev/null
585 echo $?
586
587 # floating point
588 echo foo | { read -t 0; echo reply=$REPLY; }
589 echo $?
590
591 ## STDOUT:
592 0
593 0
594 reply=
595 0
596 ## END
597 ## N-I dash/zsh/mksh stdout-json: ""
598
599 #### read -t 0.5
600 case $SH in (dash) exit ;; esac
601
602 read -t 0.5 < /dev/null
603 echo $?
604
605 ## STDOUT:
606 1
607 ## END
608 ## BUG zsh/mksh STDOUT:
609 1
610 ## END
611 ## N-I dash stdout-json: ""
612
613 #### read -t -0.5 is invalid
614 # bash appears to just take the absolute value?
615
616 read -t -0.5 < /dev/null
617 echo $?
618
619 ## STDOUT:
620 2
621 ## END
622 ## BUG bash STDOUT:
623 1
624 ## END
625 ## BUG zsh stdout-json: ""
626 ## BUG zsh status: 1
627
628 #### read -u
629 case $SH in (dash|mksh) exit ;; esac
630
631 # file descriptor
632 read -u 3 3<<EOF
633 hi
634 EOF
635 echo reply=$REPLY
636 ## STDOUT:
637 reply=hi
638 ## END
639 ## N-I dash/mksh stdout-json: ""
640
641 #### read -u syntax error
642 read -u -3
643 echo status=$?
644 ## STDOUT:
645 status=2
646 ## END
647 ## OK bash/zsh STDOUT:
648 status=1
649 ## END
650
651 #### read -N doesn't respect delimiter, while read -n does
652 case $SH in (dash|zsh|ash) exit ;; esac
653
654 echo foobar | { read -n 5 -d b; echo $REPLY; }
655 echo foobar | { read -N 5 -d b; echo $REPLY; }
656 ## STDOUT:
657 foo
658 fooba
659 ## END
660 ## OK mksh STDOUT:
661 fooba
662 fooba
663 ## END
664 ## N-I dash/zsh/ash stdout-json: ""
665
666 #### read -p (not fully tested)
667
668 # hm DISABLED if we're not going to the terminal
669 # so we're only testing that it accepts the flag here
670
671 case $SH in (dash|mksh|zsh) exit ;; esac
672
673 echo hi | { read -p 'P'; echo $REPLY; }
674 echo hi | { read -p 'P' -n 1; echo $REPLY; }
675 ## STDOUT:
676 hi
677 h
678 ## END
679 ## stderr-json: ""
680 ## N-I dash/mksh/zsh stdout-json: ""
681
682 #### read usage
683 read -n -1
684 echo status=$?
685 ## STDOUT:
686 status=2
687 ## END
688 ## OK bash stdout: status=1
689 ## BUG mksh stdout-json: ""
690 # zsh gives a fatal error? seems inconsistent
691 ## BUG zsh stdout-json: ""
692 ## BUG zsh status: 1
693
694 #### read with smooshed args
695 echo hi | { read -rn1 var; echo var=$var; }
696 ## STDOUT:
697 var=h
698 ## END
699 ## N-I dash/zsh STDOUT:
700 var=
701 ## END
702
703 #### read -r -d '' for NUL strings, e.g. find -print0
704
705
706 case $SH in (dash|zsh|mksh) exit ;; esac # NOT IMPLEMENTED
707
708 mkdir -p read0
709 cd read0
710 rm -f *
711
712 touch a\\b\\c\\d # -r is necessary!
713
714 find . -type f -a -print0 | { read -r -d ''; echo "[$REPLY]"; }
715
716 ## STDOUT:
717 [./a\b\c\d]
718 ## END
719 ## N-I dash/zsh/mksh STDOUT:
720 ## END
721
722
723 #### read from redirected directory is non-fatal error
724
725 # This tickles an infinite loop bug in our version of mksh! TODO: upgrade the
726 # version and enable this
727 case $SH in (mksh) return ;; esac
728
729 cd $TMP
730 mkdir -p dir
731 read x < ./dir
732 echo status=$?
733
734 ## STDOUT:
735 status=1
736 ## END
737 # OK mksh stdout: status=2
738 ## OK mksh stdout-json: ""
739
740 #### read -n from directory
741
742 case $SH in (dash|ash) return ;; esac # not implemented
743
744 # same hanging bug
745 case $SH in (mksh) return ;; esac
746
747 mkdir -p dir
748 read -n 3 x < ./dir
749 echo status=$?
750 ## STDOUT:
751 status=1
752 ## END
753 ## OK mksh stdout-json: ""
754 ## N-I dash/ash stdout-json: ""
755
756 #### mapfile from directory (bash doesn't handle errors)
757 case $SH in (dash|ash|mksh|zsh) return ;; esac # not implemented
758
759 mkdir -p dir
760 mapfile $x < ./dir
761 echo status=$?
762
763 ## STDOUT:
764 status=1
765 ## END
766 ## BUG bash STDOUT:
767 status=0
768 ## END
769 ## N-I dash/ash/mksh/zsh stdout-json: ""