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 |
|