Set list of arrays from a variable - BASH - arrays

It's a simple thing I'm sure, just with the right combination.
I have a file with a list of prepared arrays. I modify them using sed reading them all into a variable. I then need to set them as part of a script.
Original reference file:
var1=( "1" "%%" )
var2=( "2" "%%" )
I do my stuff with it so it becomes:
var1=( "1" "3" )
var2=( "2" "4" )
...and the list of modified arrays is all stored in a variable. I need to then read that list of arrays into a script.

Try eval:
$ x="a=asdf"; eval $x ; echo $a
outputs: asdf

Related

Bash - Print value of variable in array

I want to do something like this
A='123'
B='143'
C='999'
declare -a arr=(A B C)
for i in "{$arr[#]}"
do
echo "#i" "$i"
done
Which should give me the output of
A 123
B 143
C 999
But instead I receive the variable names, not the value in the output (I just see "A #i" in the output...
If you want to store the variable names in the loop, rather than copy their values, then you can use the following:
for i in "${arr[#]}"; do
echo "${!i}"
done
This means that the value of i is taken as a name of a variable, so you end up echoing $A, $B and $C in the loop.
Of course, this means that you can print the variable name at the same time, e.g. by using:
echo "$i: ${!i}"
It's not exactly the same, but you may also be interested in using an associative array:
declare -A assoc_arr=( [A]='123' [B]='143' [C]='999' )
for key in "${!assoc_arr[#]}"; do
echo "$key: ${assoc_arr[$key]}"
done
I suggest to add $:
declare -a arr=("$A" "$B" "$C")

bad array subscript error in associative array

I am trying to create a dictionary program in Bash with the following options : 1. Add a word
2. Update meaning
3. Print dictionary
4. Search a word
5. Search by keyword
For the same, I am creating 2 associative arrays, 1 to store the word - meaning and other to store words-keyword.
The problem is I am not able to store values in the array. Everytime I try to do it, it gives me an error
dict[$word]: bad array subscript
Here is the code for part 1
echo
echo -n "Enter a word : "
read $word
echo
echo -n "Enter it's meaning : "
read $meaning
echo
echo -n "Enter some keywords(with space in between) to describe the word : "
read $keyword
dict[$word]=$meaning
keywords[$word]=$keyword
;;
I also tried inserting the following code to remove new line as suggested in some posts but ended up with same result.
word=`echo $word | grep -s '\n'`
keyword=`echo $keyword | grep -s '\n'`
Have also tried the following way :
dict["$word"]="$meaning"
keywords["$word"]="$keyword"
;;
Output :
dict[$word]: bad array subscript
When reading a variable you preface the variable name with a $ (or wrap in $( and )).
When assigning a value to a variable you do not preface the variable name with a $.
In your example your 3x echo/read sessions are attempting to assign values to your variables, but you've prefaced your variables with $, which means your variables are not getting set as you expect; this in turn could be generating your error because $word is not set/defined (depends on version of bash).
You should be able to see what I mean with the following code snippet:
unset word
echo
echo -n "Enter a word : "
read $word
echo ".${word}."
What do you get as ouput? .. ? .<whatever_you_typed_in>. ?
You may also have a problem with your associative arrays (depending on bash version); as George has mentioned, you should play it safe and explicitly declare your associative arrays.
I would suggest editing your input script like such (remove leading $ on your read variables; explicitly declaring your associative arrays):
echo
echo -n "Enter a word : "
read word
echo
echo -n "Enter it's meaning : "
read meaning
echo
echo -n "Enter some keywords(with space in between) to describe the word : "
read keyword
# print some debug messages:
echo "word=.${word}."
echo "meaning=.${meaning}."
echo "keyword=.${keyword}."
# declare arrays as associative
declare -A dict keywords
# assign values to arrays
dict[$word]=$meaning
keywords[$word]=$keyword
# verify array indexes and values
echo "dict index(es) : ${!dict[#]}"
echo "dict value(s) : ${dict[#]}"
echo "keywords index(es): ${!keywords[#]}"
echo "keywords value(s) : ${keywords[#]}"
In my bash 4.4 , this is not raising any error but is not working correctly either:
$ w="one";m="two";d["$w"]="$m";declare -p d
declare -a d=([0]="two")
It is obvious that bash determines array d as a normal array and not as an associative array.
On the contrary, this one works fine:
$ w="one";m="two";declare -A d;d["$w"]="$m";declare -p d
declare -A d=([one]="two" )
According to bash manual, you need first to declare -A an array in order to be used as an associative one.

How to check if array values are empty, in bulk?

I want a script bash/sh/ksh which compare a lot of variables, maybe in an array, and tell me if variable is empty or not.
I think something like this, it but doesn't work.
ARRAY=(
bash="yes"
cash=""
trash="no"
empty=""
)
for var in "${ARRAY[#]}"; do
if [ "$var" == "$empty" ]
then
echo "$var is empty"
else
echo "$var is not empty"
fi
done
I want an output like this
bash is not empty
cash is empty...
If you're willing to limit your runtime environment to a recent version of bash (or modify the code to support ksh93's equivalent syntax),
#!/bin/bash
# ^^^^ -- specifically, bash 4.0 or newer
declare -A array # associative arrays need to be declared!
array=( [bash]="yes" [cash]="" [trash]="no" [empty]="" )
for idx in "${!array[#]}"; do
if [[ ${array[$idx]} ]]; then
echo "$idx is not empty"
else
echo "$idx is empty"
fi
done
To iterate over keys in an array, as opposed to values, the syntax is "${!array[#]}", as opposed to "${array[#]}"; if you merely iterate over the values, you don't know the name of the one currently being evaluated.
Alternately, let's say we aren't going to use an array at all; another way to set a namespace for variables you intend to be able to treat in a similar manner is by prefixing them:
#!/bin/bash
val_bash=yes
val_cash=
val_trash=no
val_empty=
for var in "${!val_#}"; do
if [[ ${!var} ]]; then
echo "${var#val_} is not empty"
else
echo "${var#val_} is empty"
fi
done
This works (on bash 3.x as well) because "${!prefix#}" expands to the list of variable names starting with prefix, and "${!varname}" expands to the contents of a variable whose name is itself stored in the variable varname.
Iterate over the array elements, and inside the loop for read set IFS as = to get variable and it's value in two separate variables, then check if the value is empty:
for i in "${array[#]}"; do
IFS== read var value <<<"$i"
if [ -z "$value" ]; then
echo "$var is empty"
else
echo "$var is not empty"
fi
done
Outputs:
bash is not empty
cash is empty
trash is not empty
empty is empty

Passing an array directly to a function in Shell

is it possible to pass an array directly to a function in shell/bash, without saving it first to a variable?
currently example:
function checkParameter(){
param1=("${!1}")
for a in "${param1[#]}"; do
echo "${a}"
done
param2=("${!2}")
for b in "${param2[#]}"; do
echo "${b}"
done
}
a=( "child 1 from 1" "child 2 from 1" "child 3 from 1" )
b=( "child 1 from 2" "child 2 from 2")
checkParameter a[#] b[#]
So can I pass the ( "child 1 from 1" "child 2 from 1" "child 3 from 1" ) and the ( "child 1 from 2" "child 2 from 2") somehow directly to the function checkParameter, without saving it in a and b first?
greetings and thanks,
christopher2007
"$1" is immutable. That is why your example has to store the value of it in a temporary variable. This holds true for $# regardless of whether they are passed as an array or not.
Are you sure that you need to use an array ?
checkparameters() {
for param in "$#"; do
echo "$param"
done
}
checkparameters "a" "b" "c"
To answer the question, I don't think that is possible to pass an array as function's args without transformations.
EDIT
You could try something like :
[ ~]$ cat test.sh
#!/bin/bash
declare -a a1
a1=("a" "b")
declare -a a2
a2=("c" "d")
checkParameters(){
for i in "$#"; do
echo "Content of $i :"
for j in $(eval "echo \${$(echo $i)[#]}"); do
echo $j
done
done
}
checkParameters "a1" "a2"
[ ~]$ ./test.sh
Content of a1 :
a
b
Content of a2 :
c
d
Generally, you cannot pass arrays to Bash scripts or functions as arrays:
When you pass an array on the command line, e.g., "${ary[#]}", you're not passing an array, but its elements as individual parameters; the first array element is bound to special parameter $1, the second to $2, ...
Your solution attempt employs a clever workaround by passing the name of array variables to the function, where variable indirection (${!...}) is used to access the array inside the function.[1]
By definition, this approach requires the arrays to be stored in variables up front.
As for your desire to do it without storing your arrays in a variable: You cannot pass array literals as arguments in Bash; the conceptual equivalent of that is to simply pass individual parameters.
The problem with that is that you won't be able to tell where the elements of one array end and the next one begins.
You can address that by introducing a separator parameter whose sole purpose is to indicate when an array ends.
For instance, if you know that your elements never contain a newline, you can use $\n as the separator:
#!/usr/bin/env bash
function checkParameter(){
local -i arrayNdx=1
for param; do # Loop over all parameters
[[ $param == $'\n' ]] && { (( ++arrayNdx )); continue; }
echo "From array $arrayNdx: [$param]"
done
}
# Pass the array elements as individual parameters
# and use $'\n' (a newline) to separate the elements of the 1st
# array from those of the 2nd.
checkParameter "a1-child 1" "a1-child 2" "a1-child 3" $'\n' "a2-child 1" "a2-child 2"
[1] Just to show a simplified version of your solution to make the variable-indirection part clearer:
function checkParameter(){
for a in "${!1}"; do
echo "${a}"
done
for b in "${!2}"; do
echo "${b}"
done
}
checkParameter a[#] b[#]

change array value while looping in bash

The code
SourceFolder[0]=""
SourceFolder[1]="inbound2"
SourceFolder[2]="inbound3"
for i in "${!SourceFolder[#]}"
do
if [ -z "${SourceFolder[$i]}"]; then
${SourceFolder[$i]} = "TEST"
fi
done
${SourceFolder[$i]} = "TEST" - doesn't work
it says
=: command not found
How to change value in current loop index in an array?
Because of the first space = is not interpreted as an assignment. There is a full explanation on So.
Btw ${SourceFolder[$i]} evaluate the array element, which is not what you want to do. For instance for the first one it is the empty string.
Replaces with SourceFolder[$i]=
You must change indexnumber in the your array:
ARRAYNAME[indexnumber]=value
ok, you have array is:
array=(one two three)
you can add count to your script for initialize and change element for array indexnumber, example:
#!/bin/bash
count=0
array=(one two three)
for i in ${array[#]}
do
echo "$i"
array[$count]="$i-indexnumber-is-$count"
count=$((count + 1))
echo $count
done
echo ${array[*]}
Result:
bash test-arr.sh
one
1
two
2
three
3
one-indexnumber-is-0 two-indexnumber-is-1 three-indexnumber-is-2

Resources