Passing An Array From One Bash Script to Another - arrays

I am new to writing Shell Scripts and am having some difficulties.
What I Want To Achieve
I have an array of strings in scriptOne.sh that I want to pass to scriptTwo.sh
What I Have Done So Far
I can execute the second script from inside the first using ./scriptTwo.sh and I have passed string variables from one to the other using ./scriptTwo.sh $variableOne.
The issues are when I try to pass an array variable it doesn't get passed. I have managed to get it to pass the first entry of the array using ./scriptTwo.sh "${array[#]}" however this is only one of the entries and I need all of them.
Thanks in advance for your help

Your way of passing the array is correct
./scriptTwo.sh "${array[#]}"
The problem is probably in the way how you receive it. In scriptTwo.sh, use
array=("$#")

I think we can directly read the array content from sriptOne.sh if you use a declare command.
I declare an Associative array named wes_batch_array in scriptOne.sh and I want to pass it to scriptTwo.sh so I put the command below in scriptTwo.sh:
declare -A wes_batch_array=$(awk -F '=' '{if ($1 ~ /^declare -A wes_batch_array/) {for (i=2;i<NF;i++) {printf $i"=";} printf $NF"\n";}}' < scriptOne.sh)
I've tested this command and it works fine.
If you do not use the declare command. You can echo the content of array to another middle temp file and use the awk command above to grab the content of bash array.

The way I solved this problem was to step through the array in script1.sh, then pass the array elements to script2.sh using a for loop. In my case I was passing many arrays with varying numbers of elements to the same script2.sh on different servers.
So for example:
script1.sh:
records="111111111 222222222 333333333"
myRecordsArray=($records)
for (( i=0 ; i < $(#myRecordsArray[#]} ; i++ )); do
./script2.sh ${myRecordsArray[i]}
done
script2.sh:
main () {
<some code here>
}
myRecord=$1
main $myRecord

Related

Set variable from item in array before the array is looped in a bash script

I am creating an array from the output of a command and then i am looping through the array and running commands that use each item in the array.
Before i loop through the array i want to create a variable that uses one of the values in my array. I will use this value when one of the items in the array contains a specific string.
I am not sure how to pick the value i need to set the variable from my array before i then loop through the array. I currently have this which is not working for me. I have also tried looping through to get my value but the value does not follow to the next loop, i dont think its being set and i cant keep the loop open as i am looping inside my loop.
readarray -t ARRAY < <( command that gets array of 5 hostnames )
if [[ $ARRAY[#] == *"FT-01"* ]]; then
FTP="$ARRAY"
fi
for server in "${ARRAY[#]}"; do
echo "Server: ${srv}"
echo "-------------------"
if [[ $server == *"ER-01"* ]]; then
echo " FTP server is ${FTP} and this is ${server}"
fi
done
I'm pretty sure the first if statement would never work but i am at a loss to how to pick out the the value i need from the array.
Sometimes difficulty expressing an idea is a sign that you're thinking like a C programmer rather than a shell scripter. Arrays and for loops aren't the most natural idioms in shell scripts. Consider streaming and pipes instead.
Let's say the command that gets hostnames is called list-of-hostnames. If it prints one host name per line you can filter the results with grep.
FTP=$(list-of-hostnames | grep FT-01)
If you really do want to work with an array you could use printf '%s\n' to turn it into a grep-able stream.
FTP=$(printf '%s\n' "${ARRAY[#]}" | grep FT-01)

How to pass one argument into multiple arrays

I want my bash script to process one or multiple attachments. They're passed to the script by the following parameter:
--attachment "filename(1),pathtofile(1),fileextension(1);[...];filename(n),pathtofile(n),fileextesion(n)"
--attachment "hello,/dir/hello.pdf,pdf;image,/dir/image.png,png"
This argument is stored in inputAttachments.
How can I store them in the following array?
attachmentFilename=("hello" "image")
attachmentPath=("/dir/hello.pdf" "/dir/image.png")
attachmentType=("pdf" "png")
My thought: I need to seperate inputAttachments at every semicolon and split those parts again at the comma. But how is this done and passed into the array.
I'm not exactly sure, how you are capturing the string after --attachment argument. But once you have it in a shell variable, all you need is a two-pass split which you can accomplish in the bash shell using read and a custom de-limiter to split on by setting the IFS value
IFS=\; read -r -a attachments <<<"hello,/dir/hello.pdf,pdf;image,/dir/image.png,png"
With this the string is split on ; and stored in the array attachments as individual elements which you can visualize by doing declare -p on the array name
declare -p attachments
declare -a attachments='([0]="hello,/dir/hello.pdf,pdf" [1]="image,/dir/image.png,png")'
Now loop over the array and re-split the elements on , and append to individual arrays
for attachment in "${attachments[#]}"; do
IFS=, read -r name path type <<<"$attachment"
attachmentFilename+=( "$name" )
attachmentPath+=( "$path" )
attachmentType+=( "$type" )
done

Storing Bash associative arrays

I want to store (and retrieve, of course) Bash's associative arrays and am looking for a simple way to do that.
I know that it is possible to do it using a look over all keys:
for key in "${!arr[#]}"
do
echo "$key ${arr[$key]}"
done
Retrieving it could also be done in a loop:
declare -A arr
while read key value
do
arr[$key]=$value
done < store
But I also see that set will print a version of the array in this style:
arr=([key1]="value1" [key2]="value2" )
(Unfortunately along with all other shell variables.)
Is there a simpler way for storing and retrieving an associative array than my proposed loop?
To save to a file:
declare -p arr > saved.sh
(You can also use typeset instead of declare if you prefer.)
To load from the file:
source saved.sh

bash4 read file into associative array

I am able to read file into a regular array with a single statement:
local -a ary
readarray -t ary < $fileName
Not happening is reading a file into assoc. array.
I have control over file creation and so would like to do as simply as possible w/o loops if possible at all.
So file content can be following to be read in as:
keyname=valueInfo
But I am willing to replace = with another string if cuts down on code, especially in a single line code as above.
And ...
So would it be possible to read such a file into an assoc array using something like an until or from - i.e. read into an assoc array until it hits a word, or would I have to do this as part of loop?
This will allow me to keep a lot of similar values in same file, but read into separate arrays.
I looked at mapfile as well, but does same as readarray.
Finally ...
I am creating an options list - to select from - as below:
local -a arr=("${!1}")
select option in ${arr[*]}; do
echo ${option}
break
done
Works fine - however the list shown is not sorted. I would like to have it sorted if possible at all.
Hope it is ok to put all 3 questions into 1 as the questions are similar - all on arrays.
Thank you.
First thing, associative arrays are declared with -A not -a:
local -A ary
And if you want to declare a variable on global scope, use declare outside of a function:
declare -A ary
Or use -g if BASH_VERSION >= 4.2.
If your lines do have keyname=valueInfo, with readarray, you can process it like this:
readarray -t lines < "$fileName"
for line in "${lines[#]}"; do
key=${line%%=*}
value=${line#*=}
ary[$key]=$value ## Or simply ary[${line%%=*}]=${line#*=}
done
Using a while read loop can also be an option:
while IFS= read -r line; do
ary[${line%%=*}]=${line#*=}
done < "$fileName"
Or
while IFS== read -r key value; do
ary[$key]=$value
done < "$fileName"

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