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