1 ## oils_failures_allowed: 0
2 ## compare_shells: bash dash mksh zsh
3
4 # Notes:
5 # - ash is just like dash, so don't bother testing
6 # - zsh fails several cases
7
8 #### >$file touches a file
9 rm -f myfile
10 test -f myfile
11 echo status=$?
12
13 >myfile
14 test -f myfile
15 echo status=$?
16
17 ## STDOUT:
18 status=1
19 status=0
20 ## END
21
22 ## BUG zsh STDOUT:
23 status=1
24 ## END
25
26 # regression for OSH
27 ## stderr-json: ""
28
29 #### $(< $file) yields the contents of the file
30
31 seq 2 3 > myfile
32 foo=$(< myfile)
33 argv.py "$foo"
34
35 ## STDOUT:
36 ['2\n3']
37 ## END
38
39 ## N-I dash/ash/yash STDOUT:
40 ['']
41 ## END
42
43 #### `< $file` behaves like $(< file)
44
45 seq 7 8 > myfile
46
47 x=`< myfile`
48
49 echo "[$x]"
50
51 ## STDOUT:
52 [7
53 8]
54 ## END
55 ## N-I dash/ash/yash STDOUT:
56 []
57 ## END
58
59 #### $(< file; end) is not a special case
60
61 seq 5 6 > myfile
62
63 # zsh prints the file each time!
64 # other shells do nothing?
65
66 foo=$(echo begin; < myfile)
67 echo $foo
68 echo ---
69
70 foo=$(< myfile; echo end)
71 echo $foo
72 echo ---
73
74 foo=$(< myfile; <myfile)
75 echo $foo
76 echo ---
77
78 ## STDOUT:
79 begin
80 ---
81 end
82 ---
83
84 ---
85 ## END
86
87 ## BUG zsh STDOUT:
88 begin
89 5
90 6
91 ---
92 5
93 6
94 end
95 ---
96 5
97 6
98 5
99 6
100 ---
101 ## END
102
103 #### < file in pipeline and subshell doesn't work
104 echo FOO > file2
105
106 # This only happens in command subs, which is weird
107 < file2 | tr A-Z a-z
108 ( < file2 )
109 echo end
110 ## STDOUT:
111 end
112 ## END
113 ## BUG zsh STDOUT:
114 foo
115 FOO
116 end
117 ## END
118
119 #### Leading redirect in a simple command
120 echo hello >$TMP/hello.txt # temporary fix
121 <$TMP/hello.txt cat
122 ## stdout: hello
123
124 #### Redirect in the middle of a simple command
125 f=$TMP/out
126 echo -n 1 2 '3 ' > $f
127 echo -n 4 5 >> $f '6 '
128 echo -n 7 >> $f 8 '9 '
129 echo -n >> $f 1 2 '3 '
130 echo >> $f -n 4 5 '6'
131
132 cat $f
133 echo
134 ## STDOUT:
135 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6
136 ## END
137
138 #### Redirect in command sub
139 FOO=$(echo foo 1>&2)
140 echo $FOO
141 ## stdout:
142 ## stderr: foo
143
144 #### Redirect in the middle of two assignments
145 FOO=foo >$TMP/out.txt BAR=bar printenv.py FOO BAR
146 tac $TMP/out.txt
147 ## STDOUT:
148 bar
149 foo
150 ## END
151 ## BUG zsh STDOUT:
152 ## END
153
154 #### Redirect in assignment
155 # dash captures stderr to a file here, which seems correct. Bash doesn't and
156 # just lets it go to actual stderr.
157 # For now we agree with dash/mksh, since it involves fewer special cases in the
158 # code.
159
160 FOO=$(echo foo 1>&2) 2>$TMP/no-command.txt
161 echo FILE=
162 cat $TMP/no-command.txt
163 echo "FOO=$FOO"
164 ## STDOUT:
165 FILE=
166 foo
167 FOO=
168 ## END
169 ## BUG bash STDOUT:
170 FILE=
171 FOO=
172 ## END
173
174
175 #### Redirect in function body
176 fun() { echo hi; } 1>&2
177 fun
178 ## STDOUT:
179 ## END
180 ## STDERR:
181 hi
182 ## END
183
184 #### Redirect in function body is evaluated multiple times
185 i=0
186 fun() { echo "file $i"; } 1> "$TMP/file$((i++))"
187 fun
188 fun
189 echo i=$i
190 echo __
191 cat $TMP/file0
192 echo __
193 cat $TMP/file1
194 ## STDOUT:
195 i=2
196 __
197 file 1
198 __
199 file 2
200 ## END
201 ## N-I dash stdout-json: ""
202 ## N-I dash status: 2
203
204 #### Redirect in function body AND function call
205 fun() { echo hi; } 1>&2
206 fun 2>&1
207 ## STDOUT:
208 hi
209 ## END
210 ## STDERR:
211 ## END
212
213 #### redirect bash extensions: [[ (( for ((
214
215 case $SH in dash|mksh) exit ;; esac
216
217 rm -f dbracket dparen for-expr
218
219 [[ x = x ]] > dbracket
220
221 (( 42 )) > dparen
222
223 for ((x = 0; x < 1; ++x)); do
224 echo for-expr
225 done > for-expr
226
227 wc -l dbracket dparen for-expr
228
229 ## STDOUT:
230 0 dbracket
231 0 dparen
232 1 for-expr
233 1 total
234 ## END
235
236 ## N-I dash/mksh STDOUT:
237 ## END
238
239 #### redirect if
240 if true; then
241 echo if-body
242 fi >out
243
244 cat out
245
246 ## STDOUT:
247 if-body
248 ## END
249
250 #### redirect case
251 case foo in
252 foo)
253 echo case-body
254 ;;
255 esac > out
256
257 cat out
258
259 ## STDOUT:
260 case-body
261 ## END
262
263 #### redirect while
264 while true; do
265 echo while-body
266 break
267 done > out
268
269 cat out
270
271 ## STDOUT:
272 while-body
273 ## END
274
275 #### redirect for loop
276 for i in $(seq 3)
277 do
278 echo $i
279 done > $TMP/redirect-for-loop.txt
280 cat $TMP/redirect-for-loop.txt
281 ## STDOUT:
282 1
283 2
284 3
285 ## END
286
287 #### redirect subshell
288 ( echo foo ) 1>&2
289 ## stderr: foo
290 ## stdout-json: ""
291
292 #### Prefix redirect for loop -- not allowed
293 >$TMP/redirect2.txt for i in $(seq 3)
294 do
295 echo $i
296 done
297 cat $TMP/redirect2.txt
298 ## status: 2
299 ## OK mksh status: 1
300 ## BUG zsh status: 0
301 ## BUG zsh STDOUT:
302 1
303 2
304 3
305 ## END
306
307 #### Brace group redirect
308 # Suffix works, but prefix does NOT work.
309 # That comes from '| compound_command redirect_list' in the grammar!
310 { echo block-redirect; } > $TMP/br.txt
311 cat $TMP/br.txt | wc -c
312 ## stdout: 15
313
314 #### Redirect function stdout
315 f() { echo one; echo two; }
316 f > $TMP/redirect-func.txt
317 cat $TMP/redirect-func.txt
318 ## STDOUT:
319 one
320 two
321 ## END
322
323 #### Nested function stdout redirect
324 # Shows that a stack is necessary.
325 inner() {
326 echo i1
327 echo i2
328 }
329 outer() {
330 echo o1
331 inner > $TMP/inner.txt
332 echo o2
333 }
334 outer > $TMP/outer.txt
335 cat $TMP/inner.txt
336 echo --
337 cat $TMP/outer.txt
338 ## STDOUT:
339 i1
340 i2
341 --
342 o1
343 o2
344 ## END