1 |
#!/bin/bash |
2 |
# |
3 |
# echo, read |
4 |
# later: perhaps mapfile, etc. |
5 |
|
6 |
### echo dashes |
7 |
echo - |
8 |
echo -- |
9 |
echo --- |
10 |
# stdout-json: "-\n--\n---\n" |
11 |
# BUG zsh stdout-json: "\n--\n---\n" |
12 |
|
13 |
### echo backslashes |
14 |
echo \\ |
15 |
echo '\' |
16 |
echo '\\' |
17 |
echo "\\" |
18 |
## STDOUT: |
19 |
\ |
20 |
\ |
21 |
\\ |
22 |
\ |
23 |
## BUG dash/mksh/zsh STDOUT: |
24 |
\ |
25 |
\ |
26 |
\ |
27 |
\ |
28 |
## END |
29 |
|
30 |
### echo -e backslashes |
31 |
echo -e \\ |
32 |
echo -e '\' |
33 |
echo -e '\\' |
34 |
echo -e "\\" |
35 |
## STDOUT: |
36 |
\ |
37 |
\ |
38 |
\ |
39 |
\ |
40 |
## N-I dash STDOUT: |
41 |
-e \ |
42 |
-e \ |
43 |
-e \ |
44 |
-e \ |
45 |
## END |
46 |
|
47 |
### echo -en |
48 |
echo -en 'abc\ndef\n' |
49 |
# stdout-json: "abc\ndef\n" |
50 |
# N-I dash stdout-json: "-en abc\ndef\n\n" |
51 |
|
52 |
### echo -ez (invalid flag) |
53 |
# bash differs from the other three shells, but its behavior is possibly more |
54 |
# sensible, if you're going to ignore the error. It doesn't make sense for |
55 |
# the 'e' to mean 2 different things simultaneously: flag and literal to be |
56 |
# printed. |
57 |
echo -ez 'abc\n' |
58 |
# stdout-json: "-ez abc\\n\n" |
59 |
# OK dash/mksh/zsh stdout-json: "-ez abc\n\n" |
60 |
|
61 |
### echo -e with embedded newline |
62 |
flags='-e' |
63 |
case $SH in */dash) flags='' ;; esac |
64 |
|
65 |
echo $flags 'foo |
66 |
bar' |
67 |
## STDOUT: |
68 |
foo |
69 |
bar |
70 |
## END |
71 |
|
72 |
### echo -e line continuation |
73 |
flags='-e' |
74 |
case $SH in */dash) flags='' ;; esac |
75 |
|
76 |
echo $flags 'foo\ |
77 |
bar' |
78 |
## STDOUT: |
79 |
foo\ |
80 |
bar |
81 |
## END |
82 |
|
83 |
### echo -e with C escapes |
84 |
# https://www.gnu.org/software/bash/manual/bashref.html#Bourne-Shell-Builtins |
85 |
# not sure why \c is like NUL? |
86 |
# zsh doesn't allow \E for some reason. |
87 |
echo -e '\a\b\d\e\f' |
88 |
# stdout-json: "\u0007\u0008\\d\u001b\u000c\n" |
89 |
# N-I dash stdout-json: "-e \u0007\u0008\\d\\e\u000c\n" |
90 |
|
91 |
### echo -e with whitespace C escapes |
92 |
echo -e '\n\r\t\v' |
93 |
# stdout-json: "\n\r\t\u000b\n" |
94 |
# N-I dash stdout-json: "-e \n\r\t\u000b\n" |
95 |
|
96 |
### \0 |
97 |
echo -e 'ab\0cd' |
98 |
# stdout-json: "ab\u0000cd\n" |
99 |
# dash truncates it |
100 |
# BUG dash stdout-json: "-e ab\n" |
101 |
|
102 |
### \c stops processing input |
103 |
flags='-e' |
104 |
case $SH in */dash) flags='' ;; esac |
105 |
|
106 |
echo $flags xy 'ab\cde' 'ab\cde' |
107 |
# stdout-json: "xy ab" |
108 |
# N-I mksh stdout-json: "xy abde abde" |
109 |
|
110 |
### echo -e with hex escape |
111 |
echo -e 'abcd\x65f' |
112 |
# stdout-json: "abcdef\n" |
113 |
# N-I dash stdout-json: "-e abcd\\x65f\n" |
114 |
|
115 |
### echo -e with octal escape |
116 |
flags='-e' |
117 |
case $SH in */dash) flags='' ;; esac |
118 |
|
119 |
echo $flags 'abcd\044e' |
120 |
# stdout-json: "abcd$e\n" |
121 |
|
122 |
### echo -e with 4 digit unicode escape |
123 |
flags='-e' |
124 |
case $SH in */dash) flags='' ;; esac |
125 |
|
126 |
echo $flags 'abcd\u0065f' |
127 |
# stdout-json: "abcdef\n" |
128 |
# N-I dash/ash stdout-json: "abcd\\u0065f\n" |
129 |
|
130 |
### echo -e with 8 digit unicode escape |
131 |
flags='-e' |
132 |
case $SH in */dash) flags='' ;; esac |
133 |
|
134 |
echo $flags 'abcd\U00000065f' |
135 |
# stdout-json: "abcdef\n" |
136 |
# N-I dash/ash stdout-json: "abcd\\U00000065f\n" |
137 |
|
138 |
### \0377 is the highest octal byte |
139 |
echo -en '\03777' | od -A n -t x1 | sed 's/ \+/ /g' |
140 |
# stdout-json: " ff 37\n" |
141 |
# N-I dash stdout-json: " 2d 65 6e 20 ff 37 0a\n" |
142 |
|
143 |
### \0400 is one more than the highest octal byte |
144 |
# It is 256 % 256 which gets interpreted as a NUL byte. |
145 |
echo -en '\04000' | od -A n -t x1 | sed 's/ \+/ /g' |
146 |
# stdout-json: " 00 30\n" |
147 |
# BUG ash stdout-json: " 20 30 30\n" |
148 |
# N-I dash stdout-json: " 2d 65 6e 20\n" |
149 |
|
150 |
### \0777 is out of range |
151 |
flags='-en' |
152 |
case $SH in */dash) flags='-n' ;; esac |
153 |
|
154 |
echo $flags '\0777' | od -A n -t x1 | sed 's/ \+/ /g' |
155 |
# stdout-json: " ff\n" |
156 |
# BUG mksh stdout-json: " c3 bf\n" |
157 |
# BUG ash stdout-json: " 3f 37\n" |
158 |
|
159 |
### incomplete hex escape |
160 |
echo -en 'abcd\x6' | od -A n -c | sed 's/ \+/ /g' |
161 |
# stdout-json: " a b c d 006\n" |
162 |
# N-I dash stdout-json: " - e n a b c d \\ x 6 \\n\n" |
163 |
|
164 |
### \x |
165 |
# I consider mksh and zsh a bug because \x is not an escape |
166 |
echo -e '\x' '\xg' | od -A n -c | sed 's/ \+/ /g' |
167 |
# stdout-json: " \\ x \\ x g \\n\n" |
168 |
# N-I dash stdout-json: " - e \\ x \\ x g \\n\n" |
169 |
# BUG mksh/zsh stdout-json: " \\0 \\0 g \\n\n" |
170 |
|
171 |
### incomplete octal escape |
172 |
flags='-en' |
173 |
case $SH in */dash) flags='-n' ;; esac |
174 |
|
175 |
echo $flags 'abcd\04' | od -A n -c | sed 's/ \+/ /g' |
176 |
# stdout-json: " a b c d 004\n" |
177 |
|
178 |
### incomplete unicode escape |
179 |
echo -en 'abcd\u006' | od -A n -c | sed 's/ \+/ /g' |
180 |
# stdout-json: " a b c d 006\n" |
181 |
# N-I dash stdout-json: " - e n a b c d \\ u 0 0 6 \\n\n" |
182 |
# BUG ash stdout-json: " a b c d \\ u 0 0 6\n" |
183 |
|
184 |
### \u6 |
185 |
flags='-en' |
186 |
case $SH in */dash) flags='-n' ;; esac |
187 |
|
188 |
echo $flags '\u6' | od -A n -c | sed 's/ \+/ /g' |
189 |
# stdout-json: " 006\n" |
190 |
# N-I dash/ash stdout-json: " \\ u 6\n" |
191 |
|
192 |
### \0 \1 \8 |
193 |
# \0 is special, but \1 isn't in bash |
194 |
# \1 is special in dash! geez |
195 |
flags='-en' |
196 |
case $SH in */dash) flags='-n' ;; esac |
197 |
|
198 |
echo $flags '\0' '\1' '\8' | od -A n -c | sed 's/ \+/ /g' |
199 |
# stdout-json: " \\0 \\ 1 \\ 8\n" |
200 |
# BUG dash stdout-json: " 001 \\ 8\n" |
201 |
# BUG ash stdout-json: " \\0 001 \\ 8\n" |
202 |
|
203 |
### Read builtin |
204 |
# NOTE: there are TABS below |
205 |
read x <<EOF |
206 |
A B C D E |
207 |
FG |
208 |
EOF |
209 |
echo "[$x]" |
210 |
# stdout: [A B C D E] |
211 |
# status: 0 |
212 |
|
213 |
### Read from empty file |
214 |
echo -n '' > $TMP/empty.txt |
215 |
read x < $TMP/empty.txt |
216 |
argv "status=$?" "$x" |
217 |
# stdout: ['status=1', ''] |
218 |
# status: 0 |
219 |
|
220 |
### Read builtin with no newline. |
221 |
# This is odd because the variable is populated successfully. OSH/Oil might |
222 |
# need a separate put reading feature that doesn't use IFS. |
223 |
echo -n ZZZ | { read x; echo $?; echo $x; } |
224 |
# stdout-json: "1\nZZZ\n" |
225 |
# status: 0 |
226 |
|
227 |
### Read builtin with multiple variables |
228 |
# NOTE: there are TABS below |
229 |
read x y z <<EOF |
230 |
A B C D E |
231 |
FG |
232 |
EOF |
233 |
echo "[$x/$y/$z]" |
234 |
# stdout: [A/B/C D E] |
235 |
# BUG dash stdout: [A/B/C D E ] |
236 |
# status: 0 |
237 |
|
238 |
### Read builtin with not enough variables |
239 |
set -o errexit |
240 |
set -o nounset # hm this doesn't change it |
241 |
read x y z <<EOF |
242 |
A B |
243 |
EOF |
244 |
echo /$x/$y/$z/ |
245 |
# stdout: /A/B// |
246 |
# status: 0 |
247 |
|
248 |
### Read -n (with $REPLY) |
249 |
echo 12345 > $TMP/readn.txt |
250 |
read -n 4 x < $TMP/readn.txt |
251 |
read -n 2 < $TMP/readn.txt # Do it again with no variable |
252 |
argv.py $x $REPLY |
253 |
# stdout: ['1234', '12'] |
254 |
# N-I dash/zsh stdout: [] |
255 |
|
256 |
### Read uses $REPLY (without -n) |
257 |
echo 123 > $TMP/readreply.txt |
258 |
read < $TMP/readreply.txt |
259 |
echo $REPLY |
260 |
# stdout: 123 |
261 |
# N-I dash stdout: |
262 |
|
263 |
### read -r ignores backslashes |
264 |
echo 'one\ two' > $TMP/readr.txt |
265 |
read escaped < $TMP/readr.txt |
266 |
read -r raw < $TMP/readr.txt |
267 |
argv "$escaped" "$raw" |
268 |
# stdout: ['one two', 'one\\ two'] |
269 |
|
270 |
### read -r with other backslash escapes |
271 |
echo 'one\ two\x65three' > $TMP/readr.txt |
272 |
read escaped < $TMP/readr.txt |
273 |
read -r raw < $TMP/readr.txt |
274 |
argv "$escaped" "$raw" |
275 |
# mksh respects the hex escapes here, but other shells don't! |
276 |
# stdout: ['one twox65three', 'one\\ two\\x65three'] |
277 |
# BUG mksh/zsh stdout: ['one twoethree', 'one\\ twoethree'] |
278 |
|
279 |
### read with line continuation reads multiple physical lines |
280 |
# NOTE: osh failing because of file descriptor issue. stdin has to be closed! |
281 |
tmp=$TMP/$(basename $SH)-readr.txt |
282 |
echo -e 'one\\\ntwo\n' > $tmp |
283 |
read escaped < $tmp |
284 |
read -r raw < $tmp |
285 |
argv "$escaped" "$raw" |
286 |
# stdout: ['onetwo', 'one\\'] |
287 |
# N-I dash stdout: ['-e onetwo', '-e one\\'] |
288 |
|
289 |
### read multiple vars spanning many lines |
290 |
read x y << 'EOF' |
291 |
one-\ |
292 |
two three-\ |
293 |
four five-\ |
294 |
six |
295 |
EOF |
296 |
argv "$x" "$y" "$z" |
297 |
# stdout: ['one-two', 'three-four five-six', ''] |
298 |
|
299 |
### read -r with \n |
300 |
echo '\nline' > $TMP/readr.txt |
301 |
read escaped < $TMP/readr.txt |
302 |
read -r raw < $TMP/readr.txt |
303 |
argv "$escaped" "$raw" |
304 |
# dash/mksh/zsh are bugs because at least the raw mode should let you read a |
305 |
# literal \n. |
306 |
# stdout: ['nline', '\\nline'] |
307 |
# BUG dash/mksh/zsh stdout: ['', ''] |
308 |
|
309 |
### Read with IFS=$'\n' |
310 |
# The leading spaces are stripped if they appear in IFS. |
311 |
IFS=$(echo -e '\n') |
312 |
read var <<EOF |
313 |
a b c |
314 |
d e f |
315 |
EOF |
316 |
echo "[$var]" |
317 |
# stdout: [ a b c] |
318 |
# N-I dash stdout: [a b c] |
319 |
|
320 |
### Read multiple lines with IFS=: |
321 |
# The leading spaces are stripped if they appear in IFS. |
322 |
# IFS chars are escaped with :. |
323 |
tmp=$TMP/$(basename $SH)-read-ifs.txt |
324 |
IFS=: |
325 |
cat >$tmp <<'EOF' |
326 |
\\a :b\: c:d\ |
327 |
e |
328 |
EOF |
329 |
read a b c d < $tmp |
330 |
# Use printf because echo in dash/mksh interprets escapes, while it doesn't in |
331 |
# bash. |
332 |
printf "%s\n" "[$a|$b|$c|$d]" |
333 |
# stdout: [ \a |b: c|d e|] |
334 |
|
335 |
### Read with IFS='' |
336 |
IFS='' |
337 |
read x y <<EOF |
338 |
a b c d |
339 |
EOF |
340 |
echo "[$x|$y]" |
341 |
# stdout: [ a b c d|] |
342 |
|
343 |
### Read should not respect C escapes. |
344 |
# bash doesn't respect these, but other shells do. Gah! I think bash |
345 |
# behavior makes more sense. It only escapes IFS. |
346 |
echo '\a \b \c \d \e \f \g \h \x65 \145 \i' > $TMP/read-c.txt |
347 |
read line < $TMP/read-c.txt |
348 |
echo $line |
349 |
# stdout-json: "a b c d e f g h x65 145 i\n" |
350 |
# BUG ash stdout-json: "abcdefghx65 145 i\n" |
351 |
# BUG dash/zsh stdout-json: "\u0007 \u0008\n" |
352 |
# BUG mksh stdout-json: "\u0007 \u0008 d \u001b \u000c g h e 145 i\n" |
353 |
|