1 |
#!/usr/bin/env bash |
2 |
|
3 |
### echo dashes |
4 |
echo - |
5 |
echo -- |
6 |
echo --- |
7 |
# stdout-json: "-\n--\n---\n" |
8 |
|
9 |
### echo -en |
10 |
echo -en 'abc\ndef\n' |
11 |
# stdout-json: "abc\ndef\n" |
12 |
# N-I dash stdout-json: "-en abc\ndef\n\n" |
13 |
|
14 |
### echo -ez (invalid flag) |
15 |
# bash differs from the other two shells, but its behavior is possibly more |
16 |
# sensible, if you're going to ignore the error. It doesn't make sense for the |
17 |
# 'e' to mean 2 different things simultaneously: flag and literal to be |
18 |
# printed. |
19 |
echo -ez 'abc\n' |
20 |
# stdout-json: "-ez abc\\n\n" |
21 |
# BUG dash/mksh stdout-json: "-ez abc\n\n" |
22 |
|
23 |
### exec builtin |
24 |
exec echo hi |
25 |
# stdout: hi |
26 |
|
27 |
### exec builtin with redirects |
28 |
exec 1>&2 |
29 |
echo 'to stderr' |
30 |
# stdout-json: "" |
31 |
# stderr: to stderr |
32 |
|
33 |
### exec builtin with here doc |
34 |
# This has in a separate file because both code and data can be read from |
35 |
# stdin. |
36 |
$SH spec/exec-here-doc.sh |
37 |
# stdout-json: "x=one\ny=two\nDONE\n" |
38 |
|
39 |
### cd and $PWD |
40 |
cd / |
41 |
echo $PWD |
42 |
# stdout: / |
43 |
|
44 |
### $OLDPWD |
45 |
cd / |
46 |
cd $TMP |
47 |
echo "old: $OLDPWD" |
48 |
cd - |
49 |
# stdout-json: "old: /\n/\n" |
50 |
|
51 |
### cd with no arguments |
52 |
HOME=$TMP/home |
53 |
mkdir -p $HOME |
54 |
cd |
55 |
test $(pwd) = "$HOME" && echo OK |
56 |
# stdout: OK |
57 |
|
58 |
### cd to nonexistent dir |
59 |
cd /nonexistent/dir |
60 |
echo status=$? |
61 |
# stdout: status=1 |
62 |
# OK dash/mksh stdout: status=2 |
63 |
|
64 |
### pushd/popd |
65 |
set -o errexit |
66 |
cd / |
67 |
pushd $TMP |
68 |
popd |
69 |
pwd |
70 |
# status: 0 |
71 |
# N-I dash/mksh status: 127 |
72 |
|
73 |
### Eval |
74 |
eval "a=3" |
75 |
echo $a |
76 |
# stdout: 3 |
77 |
|
78 |
### Source |
79 |
lib=$TMP/spec-test-lib.sh |
80 |
echo 'LIBVAR=libvar' > $lib |
81 |
. $lib # dash doesn't have source |
82 |
echo $LIBVAR |
83 |
# stdout: libvar |
84 |
|
85 |
### Source nonexistent |
86 |
source /nonexistent/path |
87 |
echo status=$? |
88 |
# stdout: status=1 |
89 |
# OK dash stdout: status=127 |
90 |
|
91 |
### Source with no arguments |
92 |
source |
93 |
echo status=$? |
94 |
# stdout: status=1 |
95 |
# OK bash stdout: status=2 |
96 |
# OK dash stdout: status=127 |
97 |
|
98 |
### Exit builtin |
99 |
exit 3 |
100 |
# status: 3 |
101 |
|
102 |
### Exit builtin with invalid arg |
103 |
exit invalid |
104 |
# Rationale: runtime errors are 1 |
105 |
# status: 1 |
106 |
# OK dash/bash status: 2 |
107 |
|
108 |
### Exit builtin with too many args |
109 |
exit 7 8 9 |
110 |
echo "no exit: $?" |
111 |
# status: 0 |
112 |
# stdout-json: "no exit: 1\n" |
113 |
# BUG dash status: 7 |
114 |
# BUG dash stdout-json: "" |
115 |
# OK mksh status: 1 |
116 |
# OK mksh stdout-json: "" |
117 |
|
118 |
### time block |
119 |
# bash and mksh work; dash does't. |
120 |
# TODO: osh needs to implement BraceGroup redirect properly. |
121 |
err=_tmp/time-$(basename $SH).txt |
122 |
{ |
123 |
time { |
124 |
sleep 0.01 |
125 |
sleep 0.02 |
126 |
} |
127 |
} 2> $err |
128 |
cat $err | grep --only-matching real |
129 |
# Just check that we found 'real'. |
130 |
# This is fiddly: |
131 |
# | sed -n -E -e 's/.*(0m0\.03).*/\1/' |
132 |
# |
133 |
# status: 0 |
134 |
# stdout: real |
135 |
# BUG dash status: 2 |
136 |
# BUG dash stdout-json: "" |
137 |
|
138 |
### time pipeline |
139 |
time echo hi | wc -c |
140 |
# stdout: 3 |
141 |
# status: 0 |
142 |
|
143 |
### shift |
144 |
set -- 1 2 3 4 |
145 |
shift |
146 |
echo "$@" |
147 |
shift 2 |
148 |
echo "$@" |
149 |
# stdout-json: "2 3 4\n4\n" |
150 |
# status: 0 |
151 |
|
152 |
### Shifting too far |
153 |
set -- 1 |
154 |
shift 2 |
155 |
# status: 1 |
156 |
# OK dash status: 2 |
157 |
|
158 |
### Invalid shift argument |
159 |
shift ZZZ |
160 |
# status: 1 |
161 |
# OK dash status: 2 |
162 |
# BUG mksh status: 0 |
163 |
|
164 |
### Read builtin |
165 |
# NOTE: there are TABS below |
166 |
read x <<EOF |
167 |
A B C D E |
168 |
FG |
169 |
EOF |
170 |
echo "[$x]" |
171 |
# stdout: [A B C D E] |
172 |
# status: 0 |
173 |
|
174 |
### Read builtin with no newline. |
175 |
# This is odd because the variable is populated successfully. OSH/Oil might |
176 |
# need a separate put reading feature that doesn't use IFS. |
177 |
echo -n ZZZ | { read x; echo $?; echo $x; } |
178 |
# stdout-json: "1\nZZZ\n" |
179 |
# status: 0 |
180 |
|
181 |
### Read builtin with multiple variables |
182 |
# NOTE: there are TABS below |
183 |
read x y z <<EOF |
184 |
A B C D E |
185 |
FG |
186 |
EOF |
187 |
echo "$x/$y/$z" |
188 |
# stdout: A/B/C D E |
189 |
# status: 0 |
190 |
|
191 |
### Read builtin with not enough variables |
192 |
set -o errexit |
193 |
set -o nounset # hm this doesn't change it |
194 |
read x y z <<EOF |
195 |
A B |
196 |
EOF |
197 |
echo /$x/$y/$z/ |
198 |
# stdout: /A/B// |
199 |
# status: 0 |
200 |
|
201 |
### get umask |
202 |
umask | grep '[0-9]\+' # check for digits |
203 |
# status: 0 |
204 |
|
205 |
### Read -n (with $REPLY) |
206 |
echo 12345 > $TMP/readn.txt |
207 |
read -n 4 x < $TMP/readn.txt |
208 |
read -n 2 < $TMP/readn.txt # Do it again with no variable |
209 |
argv.py $x $REPLY |
210 |
# stdout: ['1234', '12'] |
211 |
# N-I dash stdout: [] |
212 |
|
213 |
### read -r ignores backslashes |
214 |
echo 'one\ two' > $TMP/readr.txt |
215 |
read escaped < $TMP/readr.txt |
216 |
read -r raw < $TMP/readr.txt |
217 |
argv "$escaped" "$raw" |
218 |
# stdout: ['one two', 'one\\ two'] |
219 |
|
220 |
### get umask |
221 |
umask | grep '[0-9]\+' # check for digits |
222 |
# status: 0 |
223 |
|
224 |
### set umask in octal |
225 |
rm $TMP/umask-one $TMP/umask-two |
226 |
umask 0002 |
227 |
echo one > $TMP/umask-one |
228 |
umask 0022 |
229 |
echo two > $TMP/umask-two |
230 |
stat -c '%a' $TMP/umask-one $TMP/umask-two |
231 |
# status: 0 |
232 |
# stdout-json: "664\n644\n" |
233 |
# stderr-json: "" |
234 |
|
235 |
### set umask symbolically |
236 |
rm $TMP/umask-one $TMP/umask-two |
237 |
echo one > $TMP/umask-one |
238 |
umask g-w,o-w |
239 |
echo two > $TMP/umask-two |
240 |
stat -c '%a' $TMP/umask-one $TMP/umask-two |
241 |
# status: 0 |
242 |
# stdout-json: "664\n644\n" |
243 |
# stderr-json: "" |
244 |
|