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