1 ## compare_shells: dash bash mksh zsh ash
2
3 #### Remove const suffix
4 v=abcd
5 echo ${v%d} ${v%%cd}
6 ## stdout: abc ab
7
8 #### Remove const prefix
9 v=abcd
10 echo ${v#a} ${v##ab}
11 ## stdout: bcd cd
12
13 #### Remove const suffix is vectorized on user array
14 a=(1a 2a 3a)
15 argv.py ${a[@]%a}
16 ## stdout: ['1', '2', '3']
17 ## status: 0
18 ## N-I dash/mksh/ash stdout-json: ""
19 ## N-I dash/ash status: 2
20 ## N-I mksh status: 1
21
22 #### Remove const suffix is vectorized on $@ array
23 set -- 1a 2a 3a
24 argv.py ${@%a}
25 ## stdout: ['1', '2', '3']
26 ## status: 0
27 ## N-I dash/ash stdout: ['1a', '2a', '3']
28 ## N-I dash/ash status: 0
29 ## N-I mksh stdout-json: ""
30 ## N-I mksh status: 1
31
32 #### Remove const suffix from undefined
33 echo ${undef%suffix}
34 ## stdout:
35
36 #### Remove shortest glob suffix
37 v=aabbccdd
38 echo ${v%c*}
39 ## stdout: aabbc
40
41 #### Remove longest glob suffix
42 v=aabbccdd
43 echo ${v%%c*}
44 ## stdout: aabb
45
46 #### Remove shortest glob prefix
47 v=aabbccdd
48 echo ${v#*b}
49 ## stdout: bccdd
50
51 #### Remove longest glob prefix
52 v=aabbccdd
53 echo ${v##*b}
54 ## stdout: ccdd
55
56 #### Strip char class
57 v=abc
58 echo ${v%[[:alpha:]]}
59 ## stdout: ab
60 ## N-I mksh stdout: abc
61
62 #### Strip unicode prefix
63
64 show_hex() { od -A n -t c -t x1; }
65
66 # NOTE: LANG is set to utf-8.
67 # ? is a glob that stands for one character
68
69 v='μ-'
70 echo ${v#?} | show_hex
71 echo
72 echo ${v##?} | show_hex
73 echo
74
75 v='-μ'
76 echo ${v%?} | show_hex
77 echo
78 echo ${v%%?} | show_hex
79 ## STDOUT:
80 - \n
81 2d 0a
82
83 - \n
84 2d 0a
85
86 - \n
87 2d 0a
88
89 - \n
90 2d 0a
91 ## BUG dash/mksh/ash STDOUT:
92 274 - \n
93 bc 2d 0a
94
95 274 - \n
96 bc 2d 0a
97
98 - 316 \n
99 2d ce 0a
100
101 - 316 \n
102 2d ce 0a
103 ## END
104 ## BUG-2 zsh STDOUT:
105 \n
106 0a
107
108 \n
109 0a
110
111 \n
112 0a
113
114 \n
115 0a
116 ## END
117
118 #### Bug fix: Test that you can remove everything with glob
119 s='--x--'
120 argv.py "${s%%-*}" "${s%-*}" "${s#*-}" "${s##*-}"
121 ## STDOUT:
122 ['', '--x-', '-x--', '']
123 ## END
124
125 #### Test that you can remove everything with const
126 s='abcd'
127 argv.py "${s%%abcd}" "${s%abcd}" "${s#abcd}" "${s##abcd}"
128 # failure case:
129 argv.py "${s%%abcde}" "${s%abcde}" "${s#abcde}" "${s##abcde}"
130 ## STDOUT:
131 ['', '', '', '']
132 ['abcd', 'abcd', 'abcd', 'abcd']
133 ## END
134
135 #### Prepend using replacement of #
136 # This case was found in Kubernetes and others
137 array=(aa bb '')
138 argv.py ${array[@]/#/prefix-}
139 ## STDOUT:
140 ['prefix-aa', 'prefix-bb', 'prefix-']
141 ## END
142 ## N-I dash/ash status: 2
143 ## N-I dash/ash stdout-json: ""
144 ## N-I mksh status: 1
145 ## N-I mksh stdout-json: ""
146
147 #### Append using replacement of %
148 array=(aa bb '')
149 argv.py ${array[@]/%/-suffix}
150 ## STDOUT:
151 ['aa-suffix', 'bb-suffix', '-suffix']
152 ## END
153 ## N-I dash/ash status: 2
154 ## N-I dash/ash stdout-json: ""
155 ## N-I mksh status: 1
156 ## N-I mksh stdout-json: ""
157
158 #### strip unquoted and quoted [
159 # I guess dash and mksh treat unquoted [ as an invalid glob?
160 var='[foo]'
161 echo ${var#[}
162 echo ${var#"["}
163 echo "${var#[}"
164 echo "${var#"["}"
165 ## STDOUT:
166 foo]
167 foo]
168 foo]
169 foo]
170 ## END
171 ## OK mksh STDOUT:
172 [foo]
173 foo]
174 [foo]
175 foo]
176 ## END
177 ## BUG zsh stdout-json: ""
178 ## BUG zsh status: 1
179
180 #### strip unquoted and quoted []
181 # LooksLikeGlob('[]') is true
182 # I guess dash, mksh, and zsh treat unquoted [ as an invalid glob?
183 var='[]foo[]'
184 echo ${var#[]}
185 echo ${var#"[]"}
186 echo "${var#[]}"
187 echo "${var#"[]"}"
188 ## STDOUT:
189 foo[]
190 foo[]
191 foo[]
192 foo[]
193 ## END
194 ## OK mksh/zsh STDOUT:
195 []foo[]
196 foo[]
197 []foo[]
198 foo[]
199 ## END
200
201 #### strip unquoted and quoted ?
202 var='[foo]'
203 echo ${var#?}
204 echo ${var#"?"}
205 echo "${var#?}"
206 echo "${var#"?"}"
207 ## STDOUT:
208 foo]
209 [foo]
210 foo]
211 [foo]
212 ## END
213
214 #### strip unquoted and quoted [a]
215 var='[a]foo[]'
216 echo ${var#[a]}
217 echo ${var#"[a]"}
218 echo "${var#[a]}"
219 echo "${var#"[a]"}"
220 ## STDOUT:
221 [a]foo[]
222 foo[]
223 [a]foo[]
224 foo[]
225 ## END
226
227 #### Nested % and # operators (bug reported by Crestwave)
228 var=$'\n'
229 argv.py "${var#?}"
230 argv.py "${var%''}"
231 argv.py "${var%"${var#?}"}"
232 var='a'
233 argv.py "${var#?}"
234 argv.py "${var%''}"
235 argv.py "${var%"${var#?}"}"
236 ## STDOUT:
237 ['']
238 ['\n']
239 ['\n']
240 ['']
241 ['a']
242 ['a']
243 ## END
244 ## N-I dash STDOUT:
245 ['\\n']
246 ['$\\n']
247 ['$']
248 ['']
249 ['a']
250 ['a']
251 ## END
252
253 #### strip * (bug regression)
254 x=abc
255 argv.py "${x#*}"
256 argv.py "${x##*}"
257 argv.py "${x%*}"
258 argv.py "${x%%*}"
259 ## STDOUT:
260 ['abc']
261 ['']
262 ['abc']
263 ['']
264 ## END
265 ## BUG zsh STDOUT:
266 ['abc']
267 ['']
268 ['ab']
269 ['']
270 ## END
271
272 #### strip ?
273 x=abc
274 argv.py "${x#?}"
275 argv.py "${x##?}"
276 argv.py "${x%?}"
277 argv.py "${x%%?}"
278 ## STDOUT:
279 ['bc']
280 ['bc']
281 ['ab']
282 ['ab']
283 ## END
284
285 #### strip all
286 x=abc
287 argv.py "${x#abc}"
288 argv.py "${x##abc}"
289 argv.py "${x%abc}"
290 argv.py "${x%%abc}"
291 ## STDOUT:
292 ['']
293 ['']
294 ['']
295 ['']
296 ## END
297
298 #### strip none
299 x=abc
300 argv.py "${x#}"
301 argv.py "${x##}"
302 argv.py "${x%}"
303 argv.py "${x%%}"
304 ## STDOUT:
305 ['abc']
306 ['abc']
307 ['abc']
308 ['abc']
309 ## END
310
311 #### strip all unicode
312 x=μabcμ
313 echo "${x#?abc?}"
314 echo "${x##?abc?}"
315 echo "${x%?abc?}"
316 echo "${x%%?abc?}"
317 ## STDOUT:
318
319
320
321
322 ## BUG dash/mksh/ash STDOUT:
323 μabcμ
324 μabcμ
325 μabcμ
326 μabcμ
327 ## END
328
329 #### strip none unicode
330 x=μabcμ
331 argv.py "${x#}"
332 argv.py "${x##}"
333 argv.py "${x%}"
334 argv.py "${x%%}"
335 ## STDOUT:
336 ['\xce\xbcabc\xce\xbc']
337 ['\xce\xbcabc\xce\xbc']
338 ['\xce\xbcabc\xce\xbc']
339 ['\xce\xbcabc\xce\xbc']
340 ## END
341
342 #### Strip Right Brace (#702)
343 var='$foo'
344 echo 1 "${var#$foo}"
345 echo 2 "${var#\$foo}"
346
347 var='}'
348 echo 10 "${var#}}"
349 echo 11 "${var#\}}"
350 echo 12 "${var#'}'}"
351 echo 13 "${var#"}"}"
352 ## STDOUT:
353 1 $foo
354 2
355 10 }}
356 11
357 12
358 13
359 ## END
360 ## BUG zsh STDOUT:
361 1 $foo
362 2
363 10 }}
364 11
365 12 }'}
366 13
367 ## END
368
369 #### \(\) in pattern (regression)
370 x='foo()'
371 echo 1 ${x%*\(\)}
372 echo 2 ${x%%*\(\)}
373 echo 3 ${x#*\(\)}
374 echo 4 ${x##*\(\)}
375 ## STDOUT:
376 1 foo
377 2
378 3
379 4
380 ## END
381
382 #### extglob in pattern
383 case $SH in dash|zsh|ash) exit ;; esac
384
385 shopt -s extglob
386
387 x='foo()'
388 echo 1 ${x%*(foo|bar)'()'}
389 echo 2 ${x%%*(foo|bar)'()'}
390 echo 3 ${x#*(foo|bar)'()'}
391 echo 4 ${x##*(foo|bar)'()'}
392 ## STDOUT:
393 1 foo
394 2
395 3
396 4
397 ## END
398 ## N-I dash/zsh/ash stdout-json: ""