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:
457 a b c d e f g h x65 145 i
458 ## END
459 ## BUG ash STDOUT:
460 abcdefghx65 145 i
461 ## END
462 ## BUG dash/zsh stdout-json: "\u0007 \u0008\n"
463 ## BUG mksh stdout-json: "\u0007 \u0008 d \u001b \u000c g h e 145 i\n"
464
465 #### dynamic scope used to set vars
466 f() {
467 read head << EOF
468 ref: refs/heads/dev/andy
469 EOF
470 }
471 f
472 echo $head
473 ## STDOUT:
474 ref: refs/heads/dev/andy
475 ## END
476
477 #### read -a reads into array
478
479 # read -a is used in bash-completion
480 # none of these shells implement it
481 case $SH in
482 *mksh|*dash|*zsh|*/ash)
483 exit 2;
484 ;;
485 esac
486
487 read -a myarray <<'EOF'
488 a b c\ d
489 EOF
490 argv.py "${myarray[@]}"
491
492 # arguments are ignored here
493 read -r -a array2 extra arguments <<'EOF'
494 a b c\ d
495 EOF
496 argv.py "${array2[@]}"
497 argv.py "${extra[@]}"
498 argv.py "${arguments[@]}"
499 ## status: 0
500 ## STDOUT:
501 ['a', 'b', 'c d']
502 ['a', 'b', 'c\\', 'd']
503 []
504 []
505 ## END
506 ## N-I dash/mksh/zsh/ash status: 2
507 ## N-I dash/mksh/zsh/ash stdout-json: ""
508
509 #### read -d : (colon-separated records)
510 printf a,b,c:d,e,f:g,h,i | {
511 IFS=,
512 read -d : v1
513 echo "v1=$v1"
514 read -d : v1 v2
515 echo "v1=$v1 v2=$v2"
516 read -d : v1 v2 v3
517 echo "v1=$v1 v2=$v2 v3=$v3"
518 }
519 ## STDOUT:
520 v1=a,b,c
521 v1=d v2=e,f
522 v1=g v2=h v3=i
523 ## END
524 ## N-I dash STDOUT:
525 v1=
526 v1= v2=
527 v1= v2= v3=
528 ## END
529
530 #### read -d '' (null-separated records)
531 printf 'a,b,c\0d,e,f\0g,h,i' | {
532 IFS=,
533 read -d '' v1
534 echo "v1=$v1"
535 read -d '' v1 v2
536 echo "v1=$v1 v2=$v2"
537 read -d '' v1 v2 v3
538 echo "v1=$v1 v2=$v2 v3=$v3"
539 }
540 ## STDOUT:
541 v1=a,b,c
542 v1=d v2=e,f
543 v1=g v2=h v3=i
544 ## END
545 ## N-I dash STDOUT:
546 v1=
547 v1= v2=
548 v1= v2= v3=
549 ## END
550
551 #### read -rd
552 read -rd '' var <<EOF
553 foo
554 bar
555 EOF
556 echo "$var"
557 ## STDOUT:
558 foo
559 bar
560 ## END
561 ## N-I dash STDOUT:
562
563 ## END
564
565 #### read -d when there's no delimiter
566 { read -d : part
567 echo $part $?
568 read -d : part
569 echo $part $?
570 } <<EOF
571 foo:bar
572 EOF
573 ## STDOUT:
574 foo 0
575 bar 1
576 ## END
577 ## N-I dash STDOUT:
578 2
579 2
580 ## END
581
582 #### read -t 0 tests if input is available
583 case $SH in (dash|zsh|mksh) exit ;; esac
584
585 # is there input available?
586 read -t 0 < /dev/null
587 echo $?
588
589 # floating point
590 read -t 0.0 < /dev/null
591 echo $?
592
593 # floating point
594 echo foo | { read -t 0; echo reply=$REPLY; }
595 echo $?
596
597 ## STDOUT:
598 0
599 0
600 reply=
601 0
602 ## END
603 ## N-I dash/zsh/mksh stdout-json: ""
604
605 #### read -t 0.5
606 case $SH in (dash) exit ;; esac
607
608 read -t 0.5 < /dev/null
609 echo $?
610
611 ## STDOUT:
612 1
613 ## END
614 ## BUG zsh/mksh STDOUT:
615 1
616 ## END
617 ## N-I dash stdout-json: ""
618
619 #### read -t -0.5 is invalid
620 # bash appears to just take the absolute value?
621
622 read -t -0.5 < /dev/null
623 echo $?
624
625 ## STDOUT:
626 2
627 ## END
628 ## BUG bash STDOUT:
629 1
630 ## END
631 ## BUG zsh stdout-json: ""
632 ## BUG zsh status: 1
633
634 #### read -u
635 case $SH in (dash|mksh) exit ;; esac
636
637 # file descriptor
638 read -u 3 3<<EOF
639 hi
640 EOF
641 echo reply=$REPLY
642 ## STDOUT:
643 reply=hi
644 ## END
645 ## N-I dash/mksh stdout-json: ""
646
647 #### read -u syntax error
648 read -u -3
649 echo status=$?
650 ## STDOUT:
651 status=2
652 ## END
653 ## OK bash/zsh STDOUT:
654 status=1
655 ## END
656
657 #### read -N doesn't respect delimiter, while read -n does
658 case $SH in (dash|zsh|ash) exit ;; esac
659
660 echo foobar | { read -n 5 -d b; echo $REPLY; }
661 echo foobar | { read -N 5 -d b; echo $REPLY; }
662 ## STDOUT:
663 foo
664 fooba
665 ## END
666 ## OK mksh STDOUT:
667 fooba
668 fooba
669 ## END
670 ## N-I dash/zsh/ash stdout-json: ""
671
672 #### read -p (not fully tested)
673
674 # hm DISABLED if we're not going to the terminal
675 # so we're only testing that it accepts the flag here
676
677 case $SH in (dash|mksh|zsh) exit ;; esac
678
679 echo hi | { read -p 'P'; echo $REPLY; }
680 echo hi | { read -p 'P' -n 1; echo $REPLY; }
681 ## STDOUT:
682 hi
683 h
684 ## END
685 ## stderr-json: ""
686 ## N-I dash/mksh/zsh stdout-json: ""
687
688 #### read usage
689 read -n -1
690 echo status=$?
691 ## STDOUT:
692 status=2
693 ## END
694 ## OK bash stdout: status=1
695 ## BUG mksh stdout-json: ""
696 # zsh gives a fatal error? seems inconsistent
697 ## BUG zsh stdout-json: ""
698 ## BUG zsh status: 1
699
700 #### read with smooshed args
701 echo hi | { read -rn1 var; echo var=$var; }
702 ## STDOUT:
703 var=h
704 ## END
705 ## N-I dash/zsh STDOUT:
706 var=
707 ## END
708
709 #### read -r -d '' for NUL strings, e.g. find -print0
710
711
712 case $SH in (dash|zsh|mksh) exit ;; esac # NOT IMPLEMENTED
713
714 mkdir -p read0
715 cd read0
716 rm -f *
717
718 touch a\\b\\c\\d # -r is necessary!
719
720 find . -type f -a -print0 | { read -r -d ''; echo "[$REPLY]"; }
721
722 ## STDOUT:
723 [./a\b\c\d]
724 ## END
725 ## N-I dash/zsh/mksh STDOUT:
726 ## END
727
728
729 #### read from redirected directory is non-fatal error
730
731 # This tickles an infinite loop bug in our version of mksh! TODO: upgrade the
732 # version and enable this
733 case $SH in (mksh) return ;; esac
734
735 cd $TMP
736 mkdir -p dir
737 read x < ./dir
738 echo status=$?
739
740 ## STDOUT:
741 status=1
742 ## END
743 # OK mksh stdout: status=2
744 ## OK mksh stdout-json: ""
745
746 #### read -n from directory
747
748 case $SH in (dash|ash) return ;; esac # not implemented
749
750 # same hanging bug
751 case $SH in (mksh) return ;; esac
752
753 mkdir -p dir
754 read -n 3 x < ./dir
755 echo status=$?
756 ## STDOUT:
757 status=1
758 ## END
759 ## OK mksh stdout-json: ""
760 ## N-I dash/ash stdout-json: ""
761
762 #### mapfile from directory (bash doesn't handle errors)
763 case $SH in (dash|ash|mksh|zsh) return ;; esac # not implemented
764
765 mkdir -p dir
766 mapfile $x < ./dir
767 echo status=$?
768
769 ## STDOUT:
770 status=1
771 ## END
772 ## BUG bash STDOUT:
773 status=0
774 ## END
775 ## N-I dash/ash/mksh/zsh stdout-json: ""