1 |
#!/usr/bin/env bash |
2 |
# |
3 |
# Var refs are done with ${!a} |
4 |
# |
5 |
# local/declare -n is tested in spec/named-ref.test.sh. |
6 |
# |
7 |
# http://stackoverflow.com/questions/16461656/bash-how-to-pass-array-as-an-argument-to-a-function |
8 |
|
9 |
#### var ref ${!a} |
10 |
a=b |
11 |
b=c |
12 |
echo ref ${!a} ${a} |
13 |
## stdout: ref c b |
14 |
|
15 |
#### var ref: positional params |
16 |
set -- x y |
17 |
ref=1; printf "|%s" "${!ref}" $'\n' |
18 |
ref=@; printf "|%s" "${!ref}" $'\n' |
19 |
ref=*; printf "|%s" "${!ref}" $'\n' |
20 |
## STDOUT: |
21 |
|x| |
22 |
|x|y| |
23 |
|x y| |
24 |
## END |
25 |
|
26 |
#### var ref to $? with '?' |
27 |
myfunc() { |
28 |
local ref=$1 |
29 |
echo ${!ref} |
30 |
} |
31 |
myfunc FUNCNAME |
32 |
myfunc '?' # osh doesn't do this dynamically |
33 |
## STDOUT: |
34 |
myfunc |
35 |
0 |
36 |
## END |
37 |
## N-I osh STDOUT: |
38 |
myfunc |
39 |
## END |
40 |
## N-I osh status: 1 |
41 |
|
42 |
#### indirection, *then* fancy expansion features |
43 |
check_eq() { |
44 |
[ "$1" = "$2" ] || { echo "$1 vs $2"; } |
45 |
} |
46 |
check_expand() { |
47 |
val=$(eval "echo \"$1\"") |
48 |
[ "$val" = "$2" ] || { echo "$1 -> expected $2, got $val"; } |
49 |
} |
50 |
check_err() { |
51 |
e="$1" |
52 |
msg=$(eval "$e" 2>&1) && echo "bad success: $e" |
53 |
[ -z "$2" ] || [[ "$msg" == $2 ]] || echo "bad err msg: $e -> $msg" |
54 |
} |
55 |
# Nearly everything in manual section 3.5.3 "Shell Parameter Expansion" |
56 |
# is allowed after a !-indirection. |
57 |
# |
58 |
# Not allowed: any further prefix syntax. |
59 |
x=xx; xx=aaabcc |
60 |
xd=x |
61 |
check_err '${!!xd}' |
62 |
check_err '${!!x*}' |
63 |
a=(asdf x) |
64 |
check_err '${!!a[*]}' |
65 |
check_err '${!#x}' |
66 |
check_err '${!#a[@]}' |
67 |
# And an array reference binds tighter in the syntax, so goes first; |
68 |
# there's no way to spell "indirection, then array reference". |
69 |
check_expand '${!a[1]}' xx |
70 |
b=(aoeu a) |
71 |
check_expand '${!b[1]}' asdf # i.e. like !(b[1]), not (!b)[1] |
72 |
# |
73 |
# Allowed: apparently everything else. |
74 |
y=yy; yy= |
75 |
check_expand '${!y:-foo}' foo |
76 |
check_expand '${!x:-foo}' aaabcc |
77 |
z=zz; zz= |
78 |
check_eq "${!z:=foo}" foo ; check_expand '$zz' foo |
79 |
check_eq "${!z:=bar}" foo ; check_expand '$zz' foo |
80 |
w=ww; ww= |
81 |
check_err '${!w:?oops}' '*: oops' |
82 |
check_expand '${!x:?oops}' aaabcc |
83 |
check_expand '${!y:+foo}' '' |
84 |
check_expand '${!x:+foo}' foo |
85 |
check_expand '${!x:2}' abcc |
86 |
check_expand '${!x:2:2}' ab |
87 |
check_expand '${!x#*a}' aabcc |
88 |
check_expand '${!x%%c*}' aaab |
89 |
check_expand '${!x/a*b/d}' dcc |
90 |
check_expand '${!x^a}' Aaabcc |
91 |
p=pp; pp='\$ ' |
92 |
check_expand '${!p@P}' '$ ' |
93 |
echo ok |
94 |
## stdout: ok |
95 |
|
96 |
#### indirection *to* an array reference |
97 |
f() { |
98 |
printf ".%s" "${!1}" |
99 |
echo |
100 |
} |
101 |
f a[0] |
102 |
b=(x y) |
103 |
f b[0] |
104 |
f b[@] |
105 |
f "b[*]" |
106 |
# Also associative arrays. |
107 |
## STDOUT: |
108 |
. |
109 |
.x |
110 |
.x.y |
111 |
.x y |
112 |
## END |
113 |
|
114 |
#### indirection to nasty complex array references |
115 |
i=0 |
116 |
f() { |
117 |
((i++)) |
118 |
val=$(echo "${!1}") |
119 |
[ "$val" = y ] && echo -n "$i " |
120 |
} |
121 |
# Warmup: nice plain array reference |
122 |
a=(x y) |
123 |
f 'a[1]' |
124 |
# |
125 |
# Not allowed: |
126 |
# no brace expansion |
127 |
f 'a[{1,0}]' # operand expected |
128 |
# no process substitution (but see command substitution below!) |
129 |
f 'a[<(echo x)]' # operand expected |
130 |
# TODO word splitting seems interesting |
131 |
aa="1 0" |
132 |
f 'a[$aa]' # 1 0: syntax error in expression (error token is "0") |
133 |
# no filename globbing |
134 |
f 'a[b*]' # operand expected |
135 |
f 'a[1"]' # bad substitution |
136 |
# |
137 |
# Allowed: most everything else in section 3.5 "Shell Expansions". |
138 |
# tilde expansion |
139 |
( PWD=1; f 'a[~+]' ); ((i++)) |
140 |
# shell parameter expansion |
141 |
b=1 |
142 |
f 'a[$b]' |
143 |
f 'a[${c:-1}]' |
144 |
# (... and presumably most of the other features there) |
145 |
# command substitution, yikes! |
146 |
f 'a[$(echo 1)]' |
147 |
# arithmetic expansion |
148 |
f 'a[$(( 3 - 2 ))]' |
149 |
echo end |
150 |
# All of these are undocumented and probably shouldn't exist, |
151 |
# though it's always possible some will turn up in the wild and |
152 |
# we'll end up implementing them. |
153 |
## stdout: 1 end |
154 |
## OK bash stdout: 1 7 8 9 10 11 end |
155 |
|
156 |
#### indirection *to* fancy expansion features bash disallows |
157 |
check_indir() { |
158 |
result="${!1}" |
159 |
desugared_result=$(eval 'echo "${'"$1"'}"') |
160 |
[ "$2" = "$desugared_result" ] || { echo "$1 $desugared_result"; } |
161 |
} |
162 |
x=y |
163 |
y=a |
164 |
a=(x y) |
165 |
declare -A aa |
166 |
aa=([k]=r [l]=s) |
167 |
# malformed array indexing |
168 |
check_indir "a[0" |
169 |
check_indir "aa[k" |
170 |
# double indirection |
171 |
check_indir "!x" a |
172 |
check_indir "!a[0]" y |
173 |
# apparently everything else in the manual under "Shell Parameter Expansion" |
174 |
check_indir "x:-foo" y |
175 |
check_indir "x:=foo" y |
176 |
check_indir "x:?oops" y |
177 |
check_indir "x:+yy" yy |
178 |
check_indir "x:0" y |
179 |
check_indir "x:0:1" y |
180 |
check_indir "!a@" "a aa" |
181 |
# (!a[@] is elsewhere) |
182 |
check_indir "#x" 1 |
183 |
check_indir "x#y" |
184 |
check_indir "x/y/foo" foo |
185 |
check_indir "x@Q" "'y'" |
186 |
echo done |
187 |
## status: 1 |
188 |
## stdout-json: "" |
189 |
## OK bash status: 0 |
190 |
## OK bash stdout: done |
191 |
|
192 |
#### declare -n and ${!a} |
193 |
# NOTE: This is like named-ref.test.sh. OSH doesn't implement it at all. |
194 |
# Maybe we should throw an error on '-n'. |
195 |
declare -n a |
196 |
a=b |
197 |
b=c |
198 |
echo ${!a} ${a} |
199 |
## stdout: b c |
200 |
|
201 |
#### Bad var ref with ${!a} |
202 |
a='bad var name' |
203 |
echo ref ${!a} |
204 |
echo status=$? |
205 |
## STDOUT: |
206 |
status=1 |
207 |
## END |
208 |
|
209 |
# this error is fatal in osh |
210 |
## OK osh stdout-json: "" |
211 |
## OK osh status: 1 |
212 |
|
213 |
#### ${!OPTIND} (used by bash completion |
214 |
set -- a b c |
215 |
echo ${!OPTIND} |
216 |
f() { |
217 |
local OPTIND=1 |
218 |
echo ${!OPTIND} |
219 |
local OPTIND=2 |
220 |
echo ${!OPTIND} |
221 |
} |
222 |
f x y z |
223 |
## STDOUT: |
224 |
a |
225 |
x |
226 |
y |
227 |
## END |