1 ## our_shell: ysh
2
3 #### For loop over expression: List
4 var mylist = [1, 2, 3]
5 for item in (mylist) {
6 echo "item $item"
7 }
8
9 ## STDOUT:
10 item 1
11 item 2
12 item 3
13 ## END
14
15 #### For loop over expression: Dict, not BashAssoc
16
17 var mydict = {name: 'bob', age: 40}
18 for key in (mydict) {
19 echo "key $key"
20 }
21
22 # We can declare this
23 shopt --unset no_osh_builtins
24 declare -A A=([name]=bob)
25
26 # But there is no iteration
27 for key in (A) {
28 echo "key $key"
29 }
30
31 ## status: 3
32 ## STDOUT:
33 key name
34 key age
35 ## END
36
37
38 #### For loop over range
39 var myrange = 0 ..< 3
40 for i in (myrange) {
41 echo "i $i"
42 }
43
44 ## STDOUT:
45 i 0
46 i 1
47 i 2
48 ## END
49
50 #### Shell for loop with index (equivalent of enumerate())
51 for i, item in a b c {
52 echo "$i $item"
53 }
54 ## STDOUT:
55 0 a
56 1 b
57 2 c
58 ## END
59
60 #### 3 indices with (mylist) is a runtime error
61 for i, item bad in (['foo', 'bar']) {
62 echo "$i $item $bad"
63 }
64 ## status: 2
65
66 #### Shell for loop can't have 3 indices
67 for i, bad, bad in a b c {
68 echo $i $item
69 }
70 ## status: 2
71
72 #### Any for loop can't have 4 indices
73 for a, b, c, d in (['foo']) {
74 echo $i $item
75 }
76 ## status: 2
77
78 #### Expression for loop with index: List
79 for i, item in (['spam', 'eggs']) {
80 echo "$i $item"
81 }
82 ## STDOUT:
83 0 spam
84 1 eggs
85 ## END
86
87 #### Expression for loop with index: Dict (TODO: define dict iter order)
88 for key, value in ({name: 'bob', age: 40}) {
89 echo "pair $key $value"
90 }
91 ## STDOUT:
92 pair name bob
93 pair age 40
94 ## END
95
96 #### Dict: index key value loop (TODO: define dict iter order)
97 for i, key, value in ({name: 'bob', age: 40}) {
98 echo "entry $i $key $value"
99 }
100 ## STDOUT:
101 entry 0 name bob
102 entry 1 age 40
103 ## END
104
105
106 #### Equivalent of zip()
107
108 var array = :| d e f |
109
110 for i, item in a b c {
111 echo "$i $item $[array[i]]"
112 }
113
114 ## STDOUT:
115 0 a d
116 1 b e
117 2 c f
118 ## END
119
120 #### no_parse_bare_word eliminates confusion
121
122 shopt --set no_parse_bare_word
123
124 for x in mylist { # THIS FAILS
125 echo "BAD $x"
126 }
127
128 ## status: 2
129 ## STDOUT:
130 ## END
131
132
133 #### Object that's not iterable
134
135 echo hi
136 for x in (42) {
137 echo $x
138 }
139
140 ## status: 3
141 ## STDOUT:
142 hi
143 ## END
144
145 #### YSH for with brace substitution and glob
146
147 touch {foo,bar}.py
148 for i, file in *.py {README,foo}.md {
149 echo "$i $file"
150 }
151 ## STDOUT:
152 0 bar.py
153 1 foo.py
154 2 README.md
155 3 foo.md
156 ## END
157
158 #### for x in (io.stdin) {
159
160 # to avoid stdin conflict
161
162 $[ENV.SH] $[ENV.REPO_ROOT]/spec/testdata/ysh-for-stdin.ysh
163
164 ## STDOUT:
165 -1-
166 -2-
167 -3-
168
169 0 1
170 1 2
171 2 3
172
173 empty
174 done
175
176 empty2
177 done2
178
179 space
180 hi
181 ## END
182
183 #### I/O error in for x in (stdin) {
184
185 set +o errexit
186
187 # EISDIR - stdin descriptor is dir
188 $[ENV.SH] -c 'for x in (io.stdin) { echo $x }' < /
189 if test $? -ne 0; then
190 echo pass
191 fi
192
193 ## STDOUT:
194 pass
195 ## END
196
197 #### Append to List in loop extends the loop (matches JS)
198
199 # see demo/survey-loop
200
201 var mylist = [1,2,3]
202 for x in (mylist) {
203 if (x === 2) {
204 call mylist->append(99)
205 }
206 echo $x
207 }
208 ## STDOUT:
209 1
210 2
211 3
212 99
213 ## END
214
215 #### Remove from List in loop shortens it (matches JS)
216
217 # see demo/survey-loop
218
219 var mylist = [1,2,3,4]
220 for x in (mylist) {
221 if (x === 2) {
222 call mylist->pop()
223 }
224 echo $x
225 }
226 ## STDOUT:
227 1
228 2
229 3
230 ## END
231
232 #### Adding to Dict in loop does NOT extend the loop (matches JS)
233
234 # see demo/survey-loop
235
236 var mydict = {"1": null, "2": null, "3": null}
237 for x in (mydict) {
238 if (x === "2") {
239 setvar mydict["99"] = null
240 }
241 echo $x
242 }
243 ## STDOUT:
244 1
245 2
246 3
247 ## END
248
249 #### Removing from Dict in loop does NOT change the loop (does NOT match JS)
250
251 # see demo/survey-loop
252
253 var mydict = {"1": null, "2": null, "3": null, "4": null}
254 for x in (mydict) {
255 if (x === "2") {
256 call mydict->erase("1")
257 call mydict->erase("3")
258 }
259 echo $x
260 }
261 ## STDOUT:
262 1
263 2
264 3
265 4
266 ## END