Home > Software engineering >  How do I loop through elements in two bash arrays at the same time
How do I loop through elements in two bash arrays at the same time

Time:10-26

I have a bash script that should execute mongodump on multiple databases within a single mongo instance. The script should dynamically inject the Mongo-URIs and backup filenames as below :

mongodump --uri=$endpoint --authenticationDatabase admin --gzip --archive=/tmp/$filename.gz

When the script runs its facing an error - it appears its not injecting the variables correctly :

dump.sh
Starting-BACKUP
dump.sh
platforms-2022-10-25-19:05:20
sports-2022-10-25-19:05:20
mongodb://root:mypassword@mongodb-prom/platforms
mongodb://root:mypassword@mongodb-prom/sports
2022-10-25T19:05:20.392 0000    Failed: error creating intents to dump: error getting collections for database `platformsmongodb://root:mypassword@mongodb-prom/sports`: (InvalidNamespace) Invalid database name: 'platformsmongodb://root:mypassword@mongodb-prom/sports'
2022-10-25T19:05:50.409 0000    Failed: can't create session: could not connect to server: server selection error: server selection timeout, current topology: { Type: Single, Servers: [{ Addr: localhost:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp [::1]:27017: connect: connection refused }, ] }
Database backup was successful

Both the Mongo-URIs and backup filenames are being populated from arrays as below :

#declare -a BACKUP_NAMES=()
#declare -a BACKUP_ENDPOINTS=()
#declare –a DATABASES=()
#declare –a RAW_DBNAMES=()
#declare –a DATABASES=()

DATABASES =("platforms")
DATABASES =("sports")
BACKUP_RETURN_CODE=${?}
MONGODB_URI="mongodb://root:mypassword@mongodb-prom/"
NOW="$(date  "%F")-$(date  "%T")"

#array for raw db names
for DATABASE in "${DATABASES[@]}"; 
  do
  RAW_DBNAMES =("$DATABASE")
done

#array for constructing backup filenames
for DATABASE in "${DATABASES[@]}"; 
  do
  #echo $DATABASE
  BACKUP_NAMES =("$DATABASE")
done

#construct backup filenames
cnt=${#BACKUP_NAMES[@]}
for ((i=0;i<cnt;i  )); do
    BACKUP_NAMES[i]="${BACKUP_NAMES[i]}-$NOW"
    echo "${BACKUP_NAMES[i]}"
done

#construct db endpoints
for ((i=0;i<cnt;i  )); do
    uri="$MONGODB_URI${RAW_DBNAMES[i]}"
    echo "$uri"
    BACKUP_ENDPOINTS =$uri
done

#pass BACKUP_ENDPOINTS & BACKUP_FILENAMES to mongodump
for ((i=0; i<${#BACKUP_NAMES[@]}; i  )); 
    do 
    mongodump --uri="${BACKUP_ENDPOINTS[$i]}" --authenticationDatabase admin --gzip --archive=/tmp/"${BACKUP_NAMES[$i]}".gz
done

  #If the return code is non-zero then the backup was not successful
  if [[ 0 != ${BACKUP_RETURN_CODE} ]]
   then
   echo "Database backup has failed"
   exit ${BACKUP_RETURN_CODE}
else
   echo "Database backup was successful"
fi
exit 0

As a check I used these two sample arrays and I have verified that I can indeed loop through two arrays at the same time although this particular example is concatenating the elements (Is this how it works in general?):

array1=( 1 2 3 )
array2=("toronto""new york")
for ((i=0; i<${#array1[@]}; i  ));  
do echo "${array1[$i]}${array2[$i]}"; 
done

but I am not sure why in my case the strings are concatenating so wrongly.

What am I missing ?

CodePudding user response:

You don't need multiple arrays create just one and rearrange it like this:

arr=(
#   id item         product   
    1  apple        juice
    2  banana       smuzi
    3 'raw potato'  chips
#   ...
)

N=${#arr[*]} # number of items in array
C=3          # number of 'columns'

Then loop over it like so:

for ((i=0; i<$N; i =$C)); {

    read id item product <<< "${arr[@]:$i:$C}"

    echo "id: $id"
    echo "item: $item"
    echo "product: $product"
    echo '-----------------'
}

Result:

id: 1
item: apple
product: juice
-----------------
id: 2
item: banana
product: smuzi
-----------------
id: 3
item: raw
product: potato chips
-----------------

p.s. check out this backup script for example it's for psql but probably could be useful.

CodePudding user response:

Yes, it turned i was instantiating the BACKUP_ENDPOINTS array the wrong way.

This is the correct way :

#construct db endpoints
for ((i=0;i<cnt;i  )); do
    # uri="$MONGODB_URI${RAW_DBNAMES[i]}"
    # echo "$uri"
    # BACKUP_ENDPOINTS =$uri  THIS IS WRONG !!!
    BACKUP_ENDPOINTS[i]="$MONGODB_URI${RAW_DBNAMES[i]}"
done

for ENDPOINT in "${BACKUP_ENDPOINTS[@]}"; do
  echo "$ENDPOINT"
done

#pass BACKUP_ENDPOINTS & BACKUP_FILENAMES to mongodump
for ((i=0; i<${#BACKUP_NAMES[@]}; i  )); 
    do 
    mongodump --uri="${BACKUP_ENDPOINTS[$i]}" --authenticationDatabase admin --gzip --archive=/tmp/"${BACKUP_NAMES[$i]}".gz
done
  • Related