Two Arrays from one text file - arrays

I have been completely stumped by this one. I have a piece of code that spits out this...
192.168.0.1=12345
192.168.0.2=35345
192.168.0.3=72345
192.168.0.4=43345
That is written to a text file then loaded back into a program into an array.
Is there a way to split it into 2D array? The first D containing the IP address the second the other numbers. I will need to find out the IP that is linked to the numbers later in the code.
So far I just have this...
IFS=$'\r\n' GLOBIGNORE='*' command eval 'uparray=($(cat ./uptime.txt))'
I should probably mention this is running on Raspbian

if your bash version supports associative array
declare -A ip_nums
while IFS== read ip num; do
ip_nums[$num]=$ip
done <./uptime.txt
then to retreive ip from num
echo "${ip_nums[$num]}"
EDIT: To memorize the biggest number in the loop
biggest=0
while ...
...
if ((num>biggest)); then
biggest=$num
fi
done ...

Related

How can I reference an existing bash array using a 2nd variable containing the name of the array?

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[#]}

How can I split bash CLI arguments into two separate arrays for later usage?

New to StackOverflow and new to bash scripting. I have a shell script that is attempting to do the following:
cd into a directory on a remote machine. Assume I have already established a successful SSH connection.
Save the email addresses from the command line input (these could range from 1 to X number of email addresses entered) into an array called 'emails'
Save the brand IDs (integers) from the command line input (these could range from 1 to X number of brand IDs entered) into an array called 'brands'
Use nested for loops to iterate over the 'emails' and 'brands' arrays and add each email address to each brand via add.py
I am running into trouble splitting up and saving data into each array, because I do not know where the command line indices of the emails will stop, and where the indices of the brands will begin. Is there any way I can accomplish this?
command line input I expect to look as follows:
me#some-remote-machine:~$ bash script.sh person1#gmail.com person2#gmail.com person3#gmail.com ... personX#gmail.com brand1 brand2 brand3 ... brandX
The contents of script.sh look like this:
#!/bin/bash
cd some/directory
emails= ???
brands= ???
for i in $emails
do
for a in $brands
do
python test.py add --email=$i --brand_id=$a --grant=manage
done
done
Thank you in advance, and please let me know if I can clarify or provide more information.
Use a sentinel argument that cannot possibly be a valid e-mail address. For example:
$ bash script.sh person1#gmail.com person2#gmail.com '***' brand1 brand2 brand3
Then in a loop, you can read arguments until you reach the non-email; everything after that is a brand.
#!/bin/bash
cd some/directory
while [[ $1 != '***' ]]; do
emails+=("$1")
shift
done
shift # Ignore the sentinal
brands=( "$#" ) # What's left
for i in "${emails[#]}"
do
for a in "${brands[#]}"
do
python test.py add --email="$i" --brand_id="$a" --grant=manage
done
done
If you can't modify the arguments that will be passed to script.sh, then perhaps you can distinguish between an address and a brand by the presence or absence of a #:
while [[ $1 = *#* ]]; do
emails+=("$1")
shift
done
brands=("$#")
I'm assuming that the number of addresses and brands are independent. Otherwise, you can simply look at the total number of arguments $#. Say there are N of each. Then
emails=( "${#:1:$#/2}" ) # First half
brands=( "${#:$#/2+1}" ) # Second half

Bash, variables and arrays

I crawled through lots of boards but didn't find the final solution for my problem.
I have got an array, named "array0", the name is stored to a variable called arrayname. Also I've got a logged IP address, let's say 127.0.0.1, also stored in a variable, called ip.
Now I want to assign the IP to index 3 in the array like that:
"$arrayname"[3]="$ip"
So, this didn't work. I tried lots of ways how to solve that but none worked.
Is anyone out there who can tell me the final solution for this case?
Update: The given opportunities to handle the problem are great! But I forgot to mention that the array I'm working with is just sourced from another file (also written in bash). My goal is now to edit the array in the sourced file itself. Any more ideas for that?
Try
read ${arrayname}[3] <<<"$ip"
You'll need to use the declare command and indirect parameter expansion, but it's a little tricky to use with array names. It helps if you think of the index as part of the variable name, instead of an operator applied to the array name, like in most languages.
array0=(1 2 3 4 5)
arrayname=array0
name=$arrayname[3]
declare "$name=$ip"
echo "${!name}
And yet another way to do it, this time using the versatile printf.
printf -v "$arrayname[3]" %s "$ip"
demo
#!/bin/bash
array0=(a b c d e)
echo "${array0[#]}"
arrayname='array0'
ip='127.0.0.1'
printf -v "$arrayname[3]" %s "$ip"
echo "${array0[#]}"
output
a b c d e
a b c 127.0.0.1 e
See this:
# declare -a arrayname=(element1 element2 element3)
# echo ${arrayname[0]}
element1
# arrayname[4]="Yellow"
# echo ${arrayname[4]}
Yellow
# export ip="192.168.190.23"
# arrayname[5]=$ip
# echo ${arrayname[5]}
192.168.190.23
You don't have to use quotes.
After initializing the arrays, you can access the array elements using their indices as follows.
Access as:
${arrayname[3]}

(bash) How to access chunks of command output as discrete array elements?

nmcli -t -f STATE,WIFI,WWAN
gives the output
connected:enabled:disabled
which I'd like to convert to something like
Networking: connected, Wifi: enabled, WWAN: disabled
The logical solution to me is to turn this into an array. Being quite new to bash scripting, I have read that arrays are just regular variables and the elements are separated by whitespace. Currently my code is
declare -a NMOUT=$(nmcli -t -f STATE,WIFI,WWAN nm | tr ":" "\n")
which seems to sort of work for a for loop, but not if i want to ask for a specific element, as in ${NMOUT[]}. Clearly I am missing out on some key concept here. How do I access specific elements in this array?
IFS=: read -a NMOUT < <(nmcli -t -f STATE,WIFI,WWAN)
Ignacio Vazquez-Abrams provided a much better solution for creating the array. I will address the posted question.
Array's in bash are indexed by integers starting at 0.
"${NMOUT[0]}" # first element of the array
"${NMOUT[2]}" # third element of the array
"${NMOUT[#]}" # All array elements
"${NMOUT[*]}" # All array elements as a string
The following provides good information on using arrays in bash: http://mywiki.wooledge.org/BashFAQ/005

Using a variable name to create an array bash, unix

First I should perhaps explain what I want to do...
I have 'n' amounts of files with 'n' amount of lines. All I know is
that the line count will be even.
The user selects the files that they want. This is saved into an
array called ${selected_sets[#]}.
The program will print to screen a randomly selected 'odd numbered'
line from a randomly selected file.
Once the line has been printed, I don't want it printed again...
Most of it is fine, but I am having trouble creating arrays based on the contents of ${selected_sets[#]}... I think I have got my syntax all wrong :)
for i in ${selected_sets[#]}
do
x=1
linecount=$(cat $desired_path/$i | wc -l) #get line count of every set
while [ $x -le $linecount ]
do ${i}[${#${i}[#]}]=$x
x=$(($x+2)) # only insert odd numbers up to max limit of linecount
done
done
The problem is ${i}[${#${i}[#]}]=$x
I know that I can use array[${#array[#]}]=$x but I don't know how to use a variable name.
Any ideas would be most welcome (I am really stumped)!!!
In general, this type is question is solved with eval. If you want a a variable named "foo" and have a variable bar="foo", you simply do:
eval $bar=5
Bash (or any sh) treats that as if you had typed
foo=5
So you may just need to write:
eval ${i}[\${#${i}[#]}]=$x
with suitable escapes. (A useful technique is to replace 'eval' with 'echo', run the script and examine the output and make sure it looks like what you want to be evaluated.)
You can create named variables using the declare command
declare -a name=${#${i}[#]}
I'm just not sure how you would then reference those variables, I don't have time to investigate that now.
Using an array:
declare -a myArray
for i in ${selected_sets[#]}
do
x=1
linecount=$(cat $desired_path/$i | wc -l) #get line count of every set
while [ $x -le $linecount ]
do
$myArray[${#${i}[#]}]=$x
let x=x+1 #This is a bit simpler!
done
done
Beware! I didn't test any of the above. HTH

Resources