1 #!/bin/bash
2
3 ### Leading redirect
4 echo hello >$TMP/hello.txt # temporary fix
5 <$TMP/hello.txt cat
6 # stdout: hello
7
8 ### No command
9 # Hm this is valid in bash and dash. It's parsed as an assigment with a
10 # redirect, which doesn't make sense. But it's a mistake, and should be a W2
11 # warning for us.
12 FOO=bar 2>/dev/null
13
14 ### Redirect in subshell
15 FOO=$(echo foo 1>&2)
16 echo $FOO
17 # stdout:
18 # stderr: foo
19
20 ### Redirect in assignment
21 # dash captures stderr to a file here, which seems correct. Bash doesn't and
22 # just lets it go to actual stderr.
23 # For now we agree with dash/mksh, since it involves fewer special cases in the
24 # code.
25 FOO=$(echo foo 1>&2) 2>$TMP/no-command.txt
26 echo FILE=
27 cat $TMP/no-command.txt
28 echo "FOO=$FOO"
29 # stdout-json: "FILE=\nfoo\nFOO=\n"
30 # BUG bash stdout-json: "FILE=\nFOO=\n"
31
32 ### Redirect in function body.
33 func() { echo hi; } 1>&2
34 func
35 # stdout-json: ""
36 # stderr-json: "hi\n"
37
38 ### Redirect in function body is evaluated multiple times
39 i=0
40 func() { echo "file $i"; } 1> "$TMP/file$((i++))"
41 func
42 func
43 echo i=$i
44 echo __
45 cat $TMP/file0
46 echo __
47 cat $TMP/file1
48 # stdout-json: "i=2\n__\nfile 1\n__\nfile 2\n"
49 # N-I dash stdout-json: ""
50 # N-I dash status: 2
51
52 ### Redirect in function body AND function call
53 func() { echo hi; } 1>&2
54 func 2>&1
55 # stdout-json: "hi\n"
56 # stderr-json: ""
57
58 ### Descriptor redirect with spaces
59 # Hm this seems like a failure of lookahead! The second thing should look to a
60 # file-like thing.
61 # I think this is a posix issue.
62 # tag: posix-issue
63 echo one 1>&2
64 echo two 1 >&2
65 echo three 1>& 2
66 # stderr-json: "one\ntwo 1\nthree\n"
67
68 ### Filename redirect with spaces
69 # This time 1 *is* a descriptor, not a word. If you add a space between 1 and
70 # >, it doesn't work.
71 echo two 1> $TMP/file-redir1.txt
72 cat $TMP/file-redir1.txt
73 # stdout: two
74
75 ### Quoted filename redirect with spaces
76 # POSIX makes node of this
77 echo two \1 > $TMP/file-redir2.txt
78 cat $TMP/file-redir2.txt
79 # stdout: two 1
80
81 ### Descriptor redirect with filename
82 # bash/mksh treat this like a filename, not a descriptor.
83 # dash aborts.
84 echo one 1>&$TMP/nonexistent-filename__
85 echo "status=$?"
86 # stdout: status=1
87 # BUG bash stdout: status=0
88 # OK dash stdout-json: ""
89 # OK dash status: 2
90
91 ### redirect for loop
92 for i in $(seq 3)
93 do
94 echo $i
95 done > $TMP/redirect-for-loop.txt
96 cat $TMP/redirect-for-loop.txt
97 # stdout-json: "1\n2\n3\n"
98
99 ### redirect subshell
100 ( echo foo ) 1>&2
101 # stderr: foo
102 # stdout-json: ""
103
104 ### Prefix redirect for loop -- not allowed
105 >$TMP/redirect2.txt for i in $(seq 3)
106 do
107 echo $i
108 done
109 cat $TMP/redirect2.txt
110 # status: 2
111 # OK mksh status: 1
112
113 ### Brace group redirect
114 # Suffix works, but prefix does NOT work.
115 # That comes from '| compound_command redirect_list' in the grammar!
116 { echo block-redirect; } > $TMP/br.txt
117 cat $TMP/br.txt | wc -c
118 # stdout: 15
119
120 ### Redirect echo to stderr, and then redirect all of stdout somewhere.
121 { echo foo 1>&2; echo 012345789; } > $TMP/block-stdout.txt
122 cat $TMP/block-stdout.txt | wc -c
123 # stderr: foo
124 # stdout: 10
125
126 ### Redirect in the middle of two assignments
127 FOO=foo >$TMP/out.txt BAR=bar printenv.py FOO BAR
128 tac $TMP/out.txt
129 # stdout-json: "bar\nfoo\n"
130
131 ### Redirect in the middle of a command
132 f=$TMP/out
133 echo -n 1 2 '3 ' > $f
134 echo -n 4 5 >> $f '6 '
135 echo -n 7 >> $f 8 '9 '
136 echo -n >> $f 1 2 '3 '
137 echo >> $f -n 4 5 '6 '
138 cat $f
139 # stdout-json: "1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 "
140
141 ### Named file descriptor
142 exec {myfd}> $TMP/named-fd.txt
143 echo named-fd-contents >& $myfd
144 cat $TMP/named-fd.txt
145 # stdout: named-fd-contents
146 # status: 0
147 # N-I dash/mksh stdout-json: ""
148 # N-I dash/mksh status: 127
149
150 ### Redirect function stdout
151 f() { echo one; echo two; }
152 f > $TMP/redirect-func.txt
153 cat $TMP/redirect-func.txt
154 # stdout-json: "one\ntwo\n"
155
156 ### Nested function stdout redirect
157 # Shows that a stack is necessary.
158 inner() {
159 echo i1
160 echo i2
161 }
162 outer() {
163 echo o1
164 inner > $TMP/inner.txt
165 echo o2
166 }
167 outer > $TMP/outer.txt
168 cat $TMP/inner.txt
169 echo --
170 cat $TMP/outer.txt
171 # stdout-json: "i1\ni2\n--\no1\no2\n"
172
173 ### Redirect to empty string
174 f=''
175 echo s > "$f"
176 echo "result=$?"
177 set -o errexit
178 echo s > "$f"
179 echo DONE
180 # stdout: result=1
181 # status: 1
182 # OK dash stdout: result=2
183 # OK dash status: 2
184