1 #!/usr/bin/env bash
2
3 #### Here string
4 cat <<< 'hi'
5 ## stdout-json: "hi\n"
6 ## N-I dash stdout-json: ""
7 ## N-I dash status: 2
8
9 #### Here string with $
10 cat <<< $'one\ntwo\n'
11 ## stdout-json: "one\ntwo\n\n"
12 ## N-I dash stdout-json: ""
13 ## N-I dash status: 2
14
15 #### Here redirect with explicit descriptor
16 # A space betwen 0 and <<EOF causes it to pass '0' as an arg to cat.
17 cat 0<<EOF
18 one
19 EOF
20 ## stdout: one
21
22 #### Here doc from another input file descriptor
23 # NOTE: OSH fails on descriptor 9, but not descriptor 8? Is this because of
24 # the Python VM? How to inspect state?
25 read_from_fd.py 8 8<<EOF
26 here doc on descriptor
27 EOF
28 ## stdout: 8: here doc on descriptor
29
30 #### Multiple here docs with different descriptors
31 read_from_fd.py 0 3 <<EOF 3<<EOF3
32 fd0
33 EOF
34 fd3
35 EOF3
36 ## STDOUT:
37 0: fd0
38 3: fd3
39 ## END
40
41 #### Here doc with bad var delimiter
42 # Most shells accept this, but OSH is stricter.
43 cat <<${a}
44 here
45 ${a}
46 ## stdout: here
47 ## OK osh stdout-json: ""
48 ## OK osh status: 2
49
50 #### Here doc with bad comsub delimiter
51 # bash is OK with this; dash isn't. Should be a parse error.
52 cat <<$(a)
53 here
54 $(a)
55 ## stdout-json: ""
56 ## status: 2
57 ## BUG bash stdout: here
58 ## BUG bash status: 0
59 ## OK mksh status: 1
60
61 #### Here doc and < redirect -- last one wins
62 echo hello >$TMP/hello.txt # temporary fix
63 cat <<EOF <$TMP/hello.txt
64 here
65 EOF
66 ## stdout: hello
67
68 #### < redirect and here doc -- last one wins
69 cat <$TMP/hello.txt <<EOF
70 here
71 EOF
72 ## stdout: here
73
74 #### Here doc with var sub, command sub, arith sub
75 var=v
76 cat <<EOF
77 var: ${var}
78 command: $(echo hi)
79 arith: $((1+2))
80 EOF
81 ## STDOUT:
82 var: v
83 command: hi
84 arith: 3
85 ## END
86
87 #### Here doc in middle. And redirects in the middle.
88 # This isn't specified by the POSIX grammar, but it's accepted by both dash and
89 # bash!
90 echo foo > _tmp/foo.txt
91 echo bar > _tmp/bar.txt
92 cat <<EOF 1>&2 _tmp/foo.txt - _tmp/bar.txt
93 here
94 EOF
95 ## STDERR:
96 foo
97 here
98 bar
99 ## END
100
101 #### Here doc line continuation
102 cat <<EOF \
103 ; echo two
104 one
105 EOF
106 ## STDOUT:
107 one
108 two
109 ## END
110
111 #### Here doc with quote expansion in terminator
112 cat <<'EOF'"2"
113 one
114 two
115 EOF2
116 ## stdout-json: "one\ntwo\n"
117
118 #### Here doc with multiline double quoted string
119 cat <<EOF; echo "two
120 three"
121 one
122 EOF
123 ## STDOUT:
124 one
125 two
126 three
127 ## END
128
129 #### Two here docs -- first is ignored; second ones wins!
130 <<EOF1 cat <<EOF2
131 hello
132 EOF1
133 there
134 EOF2
135 ## stdout: there
136
137 #### Here doc with line continuation, then pipe. Syntax error.
138 cat <<EOF \
139 1
140 2
141 3
142 EOF
143 | tac
144 ## status: 2
145 ## OK mksh status: 1
146
147 #### Here doc with pipe on first line
148 cat <<EOF | tac
149 1
150 2
151 3
152 EOF
153 ## STDOUT:
154 3
155 2
156 1
157 ## END
158
159 #### Here doc with pipe continued on last line
160 cat <<EOF |
161 1
162 2
163 3
164 EOF
165 tac
166 ## STDOUT:
167 3
168 2
169 1
170 ## END
171
172 #### Here doc with builtin 'read'
173 # read can't be run in a subshell.
174 read v1 v2 <<EOF
175 val1 val2
176 EOF
177 echo =$v1= =$v2=
178 ## stdout: =val1= =val2=
179
180 #### Compound command here doc
181 while read line; do
182 echo X $line
183 done <<EOF
184 1
185 2
186 3
187 EOF
188 ## STDOUT:
189 X 1
190 X 2
191 X 3
192 ## END
193
194
195 #### Here doc in while condition and here doc in body
196 while cat <<E1 && cat <<E2; do cat <<E3; break; done
197 1
198 E1
199 2
200 E2
201 3
202 E3
203 ## STDOUT:
204 1
205 2
206 3
207 ## END
208
209 #### Here doc in while condition and here doc in body on multiple lines
210 while cat <<E1 && cat <<E2
211 1
212 E1
213 2
214 E2
215 do
216 cat <<E3
217 3
218 E3
219 break
220 done
221 ## STDOUT:
222 1
223 2
224 3
225 ## END
226
227 #### Here doc in while loop split up more
228 while cat <<E1
229 1
230 E1
231
232 cat <<E2
233 2
234 E2
235
236 do
237 cat <<E3
238 3
239 E3
240 break
241 done
242 ## STDOUT:
243 1
244 2
245 3
246 ## END
247
248 #### Mixing << and <<-
249 cat <<-EOF; echo --; cat <<EOF2
250 one
251 EOF
252 two
253 EOF2
254 ## stdout-json: "one\n--\ntwo\n"
255
256
257
258 #### Two compound commands with two here docs
259 while read line; do echo X $line; done <<EOF; echo ==; while read line; do echo Y $line; done <<EOF2
260 1
261 2
262 EOF
263 3
264 4
265 EOF2
266 ## stdout-json: "X 1\nX 2\n==\nY 3\nY 4\n"
267
268 #### Function def and execution with here doc
269 func() { cat; } <<EOF; echo before; func; echo after
270 1
271 2
272 EOF
273 ## stdout-json: "before\n1\n2\nafter\n"
274
275 #### Here doc as command prefix
276 <<EOF tac
277 1
278 2
279 3
280 EOF
281 ## stdout-json: "3\n2\n1\n"
282
283 # NOTE that you can have redirection AFTER the here doc thing. And you don't
284 # need a space! Those are operators.
285 #
286 # POSIX doesn't seem to have this? They have io_file, which is for
287 # filenames, and io_here, which is here doc. But about 1>&2 syntax? Geez.
288 #### Redirect after here doc
289 cat <<EOF 1>&2
290 out
291 EOF
292 ## stderr: out
293
294 #### here doc stripping tabs
295 cat <<-EOF
296 1
297 2
298 3 # 2 tabs are both stripped
299 4 # spaces are preserved
300 EOF
301 ## STDOUT:
302 1
303 2
304 3 # 2 tabs are both stripped
305 4 # spaces are preserved
306 ## END
307
308 #### Here doc within subshell with boolean
309 [[ $(cat <<EOF
310 foo
311 EOF
312 ) == foo ]]; echo $?
313 ## stdout: 0
314 ## N-I dash stdout: 127
315
316 #### Here Doc in if condition
317 if cat <<EOF; then
318 here doc in IF CONDITION
319 EOF
320 echo THEN executed
321 fi
322 ## STDOUT:
323 here doc in IF CONDITION
324 THEN executed
325 ## END
326
327 #### Nested here docs which are indented
328 cat <<- EOF
329 outside
330 $(cat <<- INSIDE
331 inside
332 INSIDE
333 )
334 EOF
335 ## STDOUT:
336 outside
337 inside
338 ## END
339
340 #### Multiple here docs in pipeline
341 # SKIPPED: hangs with osh on Debian
342 # The second instance reads its stdin from the pipe, and fd 5 from a here doc.
343 read_from_fd.py 3 3<<EOF3 | read_from_fd.py 0 5 5<<EOF5
344 fd3
345 EOF3
346 fd5
347 EOF5
348 ## STDOUT:
349 0: 3: fd3
350 5: fd5
351 ## END
352
353 #### Multiple here docs in pipeline on multiple lines
354 # SKIPPED: hangs with osh on Debian
355 # The second instance reads its stdin from the pipe, and fd 5 from a here doc.
356 read_from_fd.py 3 3<<EOF3 |
357 fd3
358 EOF3
359 read_from_fd.py 0 5 5<<EOF5
360 fd5
361 EOF5
362 ## STDOUT:
363 0: 3: fd3
364 5: fd5
365 ## END
366