LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Bash 2 dimensional array (https://www.linuxquestions.org/questions/linux-general-1/bash-2-dimensional-array-347630/)

ldp 07-28-2005 08:10 AM

Bash 2 dimensional array
 
Hi, I have this small problem with a bash script:

#!/bin/bash

echo "start full backup"

if [ ! -d /mnt/hdb/bu ]; then
echo "creating new backup folder"
mkdir /mnt/hdb/bu
fi

touch /mnt/hdb/bu/bulogerr.txt

#always make sure that you make a safe copy of the previous full backup
#so you can always fall back on the full bu of last week.

BUFILES="/mnt/hdb/bu/etc_all.tar
/mnt/hdb/bu/var_all.tar
/mnt/hdb/bu/home_all.tar
/mnt/hdb/bu/root_all.tar
/mnt/hdb/bu/apache2_all.tar
/mnt/hdb/bu/mysqldb_all.tar"

for fl in $BUFILES; do
echo -n "compressing previous $fl using gzip... "
if [ -f $fl ]; then
gzip -f -S .gz $fl >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt
if [ "$?" -eq 0 ]; then
rm $fl >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt
echo "sucess"
else
echo "failed: could not gzip $fl"
fi
else
echo "failed: $fl could not be found"
fi
done

FILES="/etc /mnt/hdb/bu/etc_all.tar
/var /mnt/hdb/bu/var_all.tar
/home /mnt/hdb/bu/home_all.tar
/root /mnt/hdb/bu/root_all.tar
/usr/local/apache2 /mnt/hdb/bu/apache2_all.tar
/usr/local/mysql/var /mnt/hdb/bu/mysqldb_all.tar"

for fl in $FILES; do
set -- $fl
echo -n "backup $1 with tar... "
tar cvf $2 $1 >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt
if [ "$?" -eq 0 ]; then
echo "sucess"
else
echo "failed: see bulogerr.txt for details"
fi
done

echo "backup done"

exit 0


the first part where I compress the .tar files works out just fine but the second part where I create the .tar files doesn't work at all.
I get the following output:

start full backup
backup /etc with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/etc_all.tar with tar... failed: see bulogerr.txt for details
backup /var with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/var_all.tar with tar... failed: see bulogerr.txt for details
backup /home with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/home_all.tar with tar... failed: see bulogerr.txt for details
backup /root with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/root_all.tar with tar... failed: see bulogerr.txt for details
backup /usr/local/apache2 with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/apache2_all.tar with tar... failed: see bulogerr.txt for details
backup /usr/local/mysql/var with tar... failed: see bulogerr.txt for details
backup /mnt/hdb/bu/mysqldb_all.tar with tar... failed: see bulogerr.txt for details
backup done

=> Instead of executing the "tar cvf $2 $1 >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt" command with both the variables, it looks like he tries it with each one at a time:

I want: tar cvf /mnt/hdb/bu/etc_all.tar /etc >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt

but all I seem to get is: tar cvf /etc >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt or: tar cvf /mnt/hdb/bu/etc_all.tar >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt

I was looking for 2dim arrays but they look quite impossible in bash...

Thanks if someone can help me out or point me in the right direction here.

kind regards,
Lieven

ldp 07-28-2005 09:26 AM

Ok, just made two one dimensional arrays with the same index, made it look like:

X=6

f[1]=/mnt/hdb/bu/etc_all.tar
f[2]=/mnt/hdb/bu/var_all.tar
f[3]=/mnt/hdb/bu/home_all.tar
f[4]=/mnt/hdb/bu/root_all.tar
f[5]=/mnt/hdb/bu/apache2_all.tar
f[6]=/mnt/hdb/bu/mysqldb_all.tar

d[1]=/etc
d[2]=/var
d[3]=/home
d[4]=/root
d[5]=/usr/local/apache2
d[6]=/usr/local/mysql/var

i=0
while [ "$i" -lt "$X" ]
do
let "i++"
echo "file: ${f[$i]} directory: ${d[$i]}"
done


=> output looks ok now.
Why-o-why are there no multi-dimensional arrays in bash?

Quigi 07-28-2005 10:06 AM

You could simplify the problem by creating a map for the 6,
* etc -> /etc
* var -> /var
...
* mysql -> /usr/local/mysql/var
You could just set "etc=/etc" and so on, and get the directory using
Code:

eval dir=$`echo $fl`
Or do the same using symlinks, or maybe bash has some associative arrays.
And then you could have a 1d loop over "etc var home root apache2 mysqldb".

But you asked for a bash solution with a 2D array. You can separate the two values that belong together with a comma, and change the following part of your original script:
Code:

FILES="/etc,/mnt/hdb/bu/etc_all.tar
/var,/mnt/hdb/bu/var_all.tar
/home,/mnt/hdb/bu/home_all.tar
/root,/mnt/hdb/bu/root_all.tar
/usr/local/apache2,/mnt/hdb/bu/apache2_all.tar
/usr/local/mysql/var,/mnt/hdb/bu/mysqldb_all.tar"

for fl in $FILES; do
set -- `echo $fl | tr , \ `
echo -n "backup $1 with tar... "

The "tr" command translates the comma, which isn't special to the shell, back to space, which is. Instead of comma you could use any other character that doesn't occur in FILES.

ldp 07-29-2005 06:00 AM

Ok, so I understand that tr can split a variable using a delimiter you can choose freely.

But I still don't understand why simply set -- $fl didn't work.
I tested it on the shell:
var="abc def"
set -- $var
echo $1 #output: abc
echo $2 #output: def

=> why doesn't it work in the loop?

regards,
Lieven

Quigi 07-29-2005 10:15 AM

The command tr "translates", hence the name. E.g., 'tr abc xyz' will replace every occurrence of a with x, of b with y, and of c with z. See 'man tr' for more. So tr doesn't officially "split" a variable -- it's bash's choice to take whitespace as separator (but not, e.g., comma, slash, letters).

The original loop didn't do what you expected because the list $FILES had 12 words, each of which was assigned to fl, one at a time. Both space and newline are whitespace, and equally separate words. By using commas instead of spaces, I changed that to 6 words.

That said, my preferred solution would still avoid 2D arrays:
Code:

etc=/etc
var=/var
home=/home
root=/root
apache2=/usr/local/apache2
mysqldb=/usr/local/mysql/var

for f in etc var home root apache2 mysqldb; do
  eval dir=$`echo $f`
  echo -n "backup $dir with tar... "
  tar cvf /mnt/hdb/bu/${f}_all.tar $dir >/dev/null 2>>/mnt/hdb/bu/bulogerr.txt
  if [ "$?" -eq 0 ]; then
    echo "sucess"
  else
    echo "failed: see bulogerr.txt for details"
  fi
done


ldp 07-29-2005 11:29 AM

Thanks for the explanation.
Altough I'm sure that the solution I tried at first works (2d table), yours looks more elegant.
kind regards,
Lieven


All times are GMT -5. The time now is 09:15 PM.