1 #!/usr/bin/env bash
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 # NOTE: LANG is set to utf-8.
64 v='μ-'
65 echo ${v#?} # ? is a glob that stands for one character
66 echo ${v##?}
67 v='-μ'
68 echo ${v%?} # ? is a glob that stands for one character
69 echo ${v%%?}
70 ## STDOUT:
71 -
72 -
73 -
74 -
75 ## BUG dash/mksh/ash stdout-repr: '\xbc-\n\xbc-\n-\xce\n-\xce\n'
76 ## BUG zsh stdout-repr: '\n\n\n\n'
77
78 #### Bug fix: Test that you can remove everything with glob
79 s='--x--'
80 argv.py "${s%%-*}" "${s%-*}" "${s#*-}" "${s##*-}"
81 ## STDOUT:
82 ['', '--x-', '-x--', '']
83 ## END
84
85 #### Test that you can remove everything with const
86 s='abcd'
87 argv.py "${s%%abcd}" "${s%abcd}" "${s#abcd}" "${s##abcd}"
88 # failure case:
89 argv.py "${s%%abcde}" "${s%abcde}" "${s#abcde}" "${s##abcde}"
90 ## STDOUT:
91 ['', '', '', '']
92 ['abcd', 'abcd', 'abcd', 'abcd']
93 ## END
94
95 #### Prepend using replacement of #
96 # This case was found in Kubernetes and others
97 array=(aa bb '')
98 argv.py ${array[@]/#/prefix-}
99 ## STDOUT:
100 ['prefix-aa', 'prefix-bb', 'prefix-']
101 ## END
102 ## N-I dash/ash status: 2
103 ## N-I dash/ash stdout-json: ""
104 ## N-I mksh status: 1
105 ## N-I mksh stdout-json: ""
106
107 #### Append using replacement of %
108 array=(aa bb '')
109 argv.py ${array[@]/%/-suffix}
110 ## STDOUT:
111 ['aa-suffix', 'bb-suffix', '-suffix']
112 ## END
113 ## N-I dash/ash status: 2
114 ## N-I dash/ash stdout-json: ""
115 ## N-I mksh status: 1
116 ## N-I mksh stdout-json: ""
117
118 #### strip unquoted and quoted [
119 # I guess dash and mksh treat unquoted [ as an invalid glob?
120 var='[foo]'
121 echo ${var#[}
122 echo ${var#"["}
123 echo "${var#[}"
124 echo "${var#"["}"
125 ## STDOUT:
126 foo]
127 foo]
128 foo]
129 foo]
130 ## END
131 ## OK dash/mksh STDOUT:
132 [foo]
133 foo]
134 [foo]
135 foo]
136 ## END
137 ## BUG zsh stdout-json: ""
138 ## BUG zsh status: 1
139
140 #### strip unquoted and quoted []
141 # LooksLikeGlob('[]') is true
142 # I guess dash, mksh, and zsh treat unquoted [ as an invalid glob?
143 var='[]foo[]'
144 echo ${var#[]}
145 echo ${var#"[]"}
146 echo "${var#[]}"
147 echo "${var#"[]"}"
148 ## STDOUT:
149 foo[]
150 foo[]
151 foo[]
152 foo[]
153 ## END
154 ## OK dash/mksh/zsh STDOUT:
155 []foo[]
156 foo[]
157 []foo[]
158 foo[]
159 ## END
160
161 #### strip unquoted and quoted ?
162 var='[foo]'
163 echo ${var#?}
164 echo ${var#"?"}
165 echo "${var#?}"
166 echo "${var#"?"}"
167 ## STDOUT:
168 foo]
169 [foo]
170 foo]
171 [foo]
172 ## END
173
174 #### strip unquoted and quoted [a]
175 var='[a]foo[]'
176 echo ${var#[a]}
177 echo ${var#"[a]"}
178 echo "${var#[a]}"
179 echo "${var#"[a]"}"
180 ## STDOUT:
181 [a]foo[]
182 foo[]
183 [a]foo[]
184 foo[]
185 ## END
186
187 #### Nested % and # operators (bug reported by Crestwave)
188 var=$'\n'
189 argv.py "${var#?}"
190 argv.py "${var%''}"
191 argv.py "${var%"${var#?}"}"
192 var='a'
193 argv.py "${var#?}"
194 argv.py "${var%''}"
195 argv.py "${var%"${var#?}"}"
196 ## STDOUT:
197 ['']
198 ['\n']
199 ['\n']
200 ['']
201 ['a']
202 ['a']
203 ## END
204 ## N-I dash STDOUT:
205 ['\\n']
206 ['$\\n']
207 ['$']
208 ['']
209 ['a']
210 ['a']
211 ## END
212
213 #### strip * (bug regression)
214 x=abc
215 argv.py "${x#*}"
216 argv.py "${x##*}"
217 argv.py "${x%*}"
218 argv.py "${x%%*}"
219 ## STDOUT:
220 ['abc']
221 ['']
222 ['abc']
223 ['']
224 ## END
225 ## BUG zsh STDOUT:
226 ['abc']
227 ['']
228 ['ab']
229 ['']
230 ## END
231
232 #### strip ?
233 x=abc
234 argv.py "${x#?}"
235 argv.py "${x##?}"
236 argv.py "${x%?}"
237 argv.py "${x%%?}"
238 ## STDOUT:
239 ['bc']
240 ['bc']
241 ['ab']
242 ['ab']
243 ## END
244
245 #### strip all
246 x=abc
247 argv.py "${x#abc}"
248 argv.py "${x##abc}"
249 argv.py "${x%abc}"
250 argv.py "${x%%abc}"
251 ## STDOUT:
252 ['']
253 ['']
254 ['']
255 ['']
256 ## END
257
258 #### strip none
259 x=abc
260 argv.py "${x#}"
261 argv.py "${x##}"
262 argv.py "${x%}"
263 argv.py "${x%%}"
264 ## STDOUT:
265 ['abc']
266 ['abc']
267 ['abc']
268 ['abc']
269 ## END
270
271 #### strip all unicode
272 x=μabcμ
273 echo "${x#?abc?}"
274 echo "${x##?abc?}"
275 echo "${x%?abc?}"
276 echo "${x%%?abc?}"
277 ## STDOUT:
278
279
280
281
282 ## BUG dash/mksh/ash STDOUT:
283 μabcμ
284 μabcμ
285 μabcμ
286 μabcμ
287 ## END
288
289 #### strip none unicode
290 x=μabcμ
291 argv.py "${x#}"
292 argv.py "${x##}"
293 argv.py "${x%}"
294 argv.py "${x%%}"
295 ## STDOUT:
296 ['\xce\xbcabc\xce\xbc']
297 ['\xce\xbcabc\xce\xbc']
298 ['\xce\xbcabc\xce\xbc']
299 ['\xce\xbcabc\xce\xbc']
300 ## END