I want to do a script of the sort:
#!/usr/bin/ksh93
typeset -A foo
function fillItUP {
typeset -A newarr
newarr["this"]="bar"
newarr["another"]="tut"
inputarrayname=$1
nameref $inputarrayname=newarr
}
With an output of the sort:
fillItUP "foo"
echo ${foo["this"]}
bar
I guess its pretty obvious, but what I thought of doing was using a double indirect reference to manipulate the array inside the function and later use it outside. Didn't work :(
Anyone would know a way to achieve this?
Thanks for the explanation . I understand what you are trying to pull off.
Now here is the working code
#!/usr/bin/ksh93
typeset -A foo
foo["this"]="old bar"
foo["another"]="old tut"
function fillItUP {
nameref newarr=$1
newarr["this"]="bar"
newarr["another"]="tut"
## nameref newarr=$1
}
fillItUP foo
echo ${foo["this"]}
The whole idea of nameref of typeset -n is to feed a variable from the one scope to the other. In your sample code, you were first allocating a local array to your function fillItUP (NOTE: why local ?? Read this on ...typeset and scope ) and then trying to point the local array to foo. If you want to change foo.. you need to make the local variable point to foo and then change it.
If you uncomment the 'commented nameref' and comment the 'uncommented nameref'
You will see that the value of foo is still "old bar".
If you execute the code I have added as it is, you will see that the value if foo[this]=bar and not the "old bar"
Hope this helped.
NOTE: You can comment out the initial "old" contents of foo and try it too :)
Related
There are multiple ways to get a result from a function in a bash script, one is to use reference variables like local -n out_ref="$1, which is also my preferred way.
My bash version is:
GNU bash, Version 5.0.3(1)-release
Recently, one of my bash functions needed to produce a associative array as a result, like in this example code:
#!/bin/bash
testFunction() {
local -n out_ref="$1"
out_ref[name]="Fry"
out_ref[company]="Planet Express"
}
declare -A employee
testFunction employee
echo -e "employee[name]: ${employee[name]}"
echo -e "employee[company]: ${employee[company]}"
I declare the variable employee as an associative array with declare -A.
The output is:
employee[name]: Fry
employee[company]: Planet Express
If I remove the line declare -A employee, the output is:
employee[name]: Planet Express
employee[company]: Planet Express
Is there a way to move the declaration of the associative array into the function, so the user of that function does not need to do it beforehand?
Use declare -Ag "$1" inside the function, so that you declare employee as a global variable.
Without declare -A employee, employee is basically treated like an ordinary indexed array. In that context, name and employee are both undefined variables evaluated in an arithmetic context, so both evaluate to 0.
I'm not entirely sure how local -n is implemented (local -nA is not allowed to mark the reference as an associative array), but it appears that lacking a "real" associate array to assign to, the value of employee is just whatever the last value assigned to any key of the reference out_ref. (Probably the same as above: both name and company evaluate to 0 in the arithmetic context, so you are assigning to out_ref[0] twice (and because out_ref does not refer to an array-marked name, you are just assigning to out_ref itself.)
Expanding on what these better minds have provided, here's a functioning example that shows it in actual use.
A() {
declare -Ag "$1"
local -n ref="$1"
ref[A]='in A'
}
B() {
declare -Ag "$1"
local -n ref="$1"
ref[B]='in B'
}
A foo
B foo
declare -p foo
Saved and executed as a file named tst, here's the run and the output -
$: ./tst
declare -A foo=([A]="in A" [B]="in B" )
Note the "redeclaration" of the global variable in multiple functions does not impugn the data integrity.
My closest most helpful matches when I searched for an answer ahead of posting:
Iterate over array in shell whose name is stored in a variable
How to use an argument/parameter name as a variable in a bash script
How to iterate over an array using indirect reference?
My attempt with partial success:
#!/bin/bash
declare -a large_furry_mammals
declare -a array_reference
# I tried both declaring array_reference as an array and
# not declaring it as an array. no change in behavior.
large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
tmp="${size}_furry_${category}"
eval array_reference='$'$tmp
echo tmp=$tmp
echo array_reference[0]=${array_reference[0]}
echo array_reference[1]=${array_reference[1]}
Output
tmp=large_furry_mammals
array_reference[0]=horse
array_reference[1]=
Expectation
I would have expected to get the output zebra when I echoed array_reference[1].
...but I'm missing some subtlety...
Why can I not access elements of the index array beyond index 0?
This suggests that array_reference is not actually being treated as an array.
I'm not looking to make a copy of the array. I want to reference (what will be) a static array based on a variable pointing to that array, i.e., ${size}_furry_${category} -> large_furry_mammals.
I've been successful with the general idea here using the links I've posted but only as long as its not an array. When it's an array, it's falling down for me.
Addendum Dec 5, 2018
bash 4.3 is not available in this case. #benjamin's answer does work on under 4.3.
I'll be needing to loop over the resulting array variable's contents. This kinda dumb example I gave involving mammals was just to describe the concept. There's actually a real world case around this. I have set of static reference arrays and an input string would be parsed to select which array was relevant and then I will loop over the array that was selected. I could do a case statement but with more than 100 reference arrays that would be the direct but overly verbose way to do it.
This pseudo code is probably better example of what I'm going after.
m1_array=(x a r d)
m2_array=(q 3 fg d)
m3_array=(c e p)
Based on some logic...select which array prefix you need.
x=m1
for each element in ${x}_array
do
some-task
done
I'm doing some testing with #eduardo's solution to see if I can adapt the way he references the variables to get to my endgame.
** Addendum #2 December 14, 2018 **
Solution
I found it! Working with #eduardo's example I came up with the following:
#!/bin/bash
declare -a large_furry_mammals
#declare -a array_reference
large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
tmp="${size}_furry_${category}[#]"
for element in "${!tmp}"
do
echo $element
done
Here is what execution looks like. We successfully iterate over the elements of the array string that was built dynamically.
./example3b.sh
horse
zebra
gorilla
Thank you everyone.
If you have Bash 4.3 or newer, you can use namerefs:
large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
declare -n array_reference=${size}_furry_$category
printf '%s\n' "${array_reference[#]}"
with output
horse
zebra
gorilla
This is a reference, so changes are reflected in both large_furry_mammals and array_reference:
$ array_reference[0]='donkey'
$ large_furry_mammals[3]='llama'
$ printf '%s\n' "${array_reference[#]}"
donkey
zebra
gorilla
llama
$ printf '%s\n' "${large_furry_mammals[#]}"
donkey
zebra
gorilla
llama
declare -a large_furry_mammals
declare -a array_reference
large_furry_mammals=(horse zebra gorilla)
size=large
category=mammals
echo ${large_furry_mammals[#]}
tmp="${size}_furry_${category}"
array_reference=${tmp}"[1]"
eval ${array_reference}='bear'
echo tmp=$tmp
echo ${large_furry_mammals[#]}
I have a Bash script that I can't figure out how to quote a variable in.
Any help would be greatly appreciated.
This code works perfectly:
myfunction() {
for i in "${BASE_ARRAY[#]}"
do
I want to pass the name of my array as a variable to the function so I can reuse it with other arrays. This is the code I am trying that fails:
myfunction() {
for i in "${$1[#]}"
do
Then I pass the following to the function:
myfunction BASE_ARRAY
I've never had success passing arrays into functions.
For me, the two options are always to pass content into a function, or (since bash 4.3) pass in an array name which will be accessed using a reference. Consider the following example.
#!/usr/bin/env bash
myfunc() {
local -n arr=$1
printf '%s\n' "${arr[1]}"
arr[1]=HELLO
}
a=(one two three)
myfunc a
printf '%s\n' "${a[1]}"
which produces:
$ ./sample
two
HELLO
Note that local -n is like declare -n in that it doesn't provide a local copy of the array, but rather a local pointer to the original content. In this example, if you change $arr[], you are actually changing the original array, $a[].
The traditional method of passing array content to a function has been described so many times here on StackOverflow that it hardly bears mentioning; you'll have no difficulty finding examples.
Try this:
myfunction() {
local x="$1[#]"
for i in "${!x}"
do
Indirect references in Bash look like "${!VARIABLE_CONTAINING_NAME_TO_EXPAND}". It is straightforward for variables that are not arrays.
But when you need to access an item in an array (or all items like in your case), you need to put the whole reference in the variable to be expanded.
How can i refer an indirect variable in the korn shell
Suppose i've an Variable
FLAG_1=0
and i want this variable value to changed from the array that i've set
set -A Flags_array
Flags_array[0]=? #how to achieve this here
For example if i try
Flags_array[0]=$FLAG_1 # this won't work as this assign the value
I tried doing something like this
Flags_array[0]=FLAG_1
echo ${Flags_array[0]}
But this gives output FLAG_1
I tried using nameref but it's giving me error
$ nameref Flags_array[0]=FLAG_1
ksh: nameref: not found
Please tell me what is proper way to achieving this ?
because what i want to do is later
if i write Flags_array[0]=10 the value of FLAG_1 becomes 10
i just tried it on my console, and it seems that you are using an invalid option for set.... try using small a instead of capital:
set -a Flags_array
just did it like this in my console and worked:
set -a array
number=5
array[0]= $number
echo $array[0] --------> from which i got result : 5[0]
also just to know for future reference, you dont need the curly brackets {}, these you use only if you are calling a variable in a place were actual data would be expected (sorry for the expression), for example here you would need them:
were e.g. random=5
sed "${random}s/^.*$/1/" test.txt
Hope this clears things for you.. :)
This is my simple array:
typeset -A foo
foo["first"]="first Value"
foo["second"]="second Value"
And I want to do a function that would pick this array, do something and return it back to the script. e.g.
function changeThat {
eval tmp=\$$1
tmp["$2"]=$3
return $tmp
}
I a way could go along in the script and do something like:
foo=changeThat foo "first" "a new first value"
And get a pretty result like
echo ${foo["first"]}
a new first value
Now this doesn't work... Well, I'm aware the syntax is prob not quite right. But I got really lost going through the nuances of evals and scape echo (not to say that I hate it from the bottom of my soul). Besides, my reference is for bash and wouldn't be the first time I miss some trick when it comes to ksh - For instance, I've been so far in ksh88, which does't even have associative arrays, while most people say it should. Turns out that my AIX box does not agree. -_-
thanks!
You can define your function like this:
function changeThat {
typeset -n ref="$1"
typeset key="$2"
typeset value="$3"
ref["$key"]="$value"
}
typeset -n ref defines the ref variable as a reference to the variable specified by it's value.
When you make this call to the function:
changeThat foo this "mow the lawn"
The variable ref in function changeThat references the variable foo. Using ref is now just like using foo. After calling changeThat
print ${foo["this"]}
will now output "mow the lawn".