Combining multiple variables into new variable

Hello, I am a new joiner to the forum, and have what i hope is a simple question, however I can't seem to find the answer so maybe it is not available within bash scripting.

I intend to use the below script to archive files from multiple directories at once by using a loop, and a variable (n) which increases by one each loop.

The problem is that when i connect two variables, if i define a variable with that output, it is not called, only the text is output.
Hopefully you can see what im trying to do and it will explain itself;

#!/bin/bash

n=1
a=/archive
dir_1=/home/gohara/test/sd1
dir_2=/home/gohara/test/sd2
dir_3=/home/gohara/test/sd3
filemask_1=TAV*.???
filemask_2=TAV*.???
filemask_3=TAV*.???
fileage_1=30
fileage_2=30
fileage_3=30

while [ $n -le 3 ]

do

#If dir_n is NOT NULL
if [ -n $dir_$n ]; then

find $dir_$n/$filemask_$n -type f -mtime +fileage_$n -exec mv {} $dir_$n$a \;

#Repeat task for 3 directories listed above
n=`expr $n + 1`

fi
done

Always handy to know a carpenter :wink:

#!/bin/bash

n=1
a=/archive
dir_1=/home/gohara/test/sd1
dir_2=/home/gohara/test/sd2
dir_3=/home/gohara/test/sd3
filemask_1='TAV\*.???' # avoid interpolation here
filemask_2='TAV\*.???' # And include an escape
filemask_3='TAV\*.???'# for the call to find
fileage_1=30
fileage_2=30
fileage_3=30

while [ $n -le 3 ]
do
    #If dir_n is NOT NULL
    if [ -n ${dir_$n} ]; then
       find ${dir_$n}/${filemask_$n} -type f -mtime +fileage_$n -exec mv {} ${dir_$n}$a \;

       #Repeat task for 3 directories listed above
       n=`expr $n + 1`
    fi
done

You can surround the variable name with braces to isolate it from surrounding text.

You have to use when you want to build a variable name using another variable. like dir_1 using variable n.

cgi@tioman> (/home/cgi) $ dir_1="abc"
cgi@tioman> (/home/cgi) $ n=1
cgi@tioman> (/home/cgi) $ echo $dir_$n
1

Here you won't get the value, because it tries $dir_ as one variable which is empty and $n as another variable which is 1, but below method works.

cgi@tioman> (/home/cgi) $ eval echo '$'dir_$n
abc
cgi@tioman> (/home/cgi) $


---------- Post updated at 01:04 PM ---------- Previous update was at 01:00 PM ----------

cgi@tioman> (/home/cgi) $ echo ${dir_$n}
-bash: ${dir_$n}: bad substitution
cgi@tioman> (/home/cgi) $
cgi@tioman> (/home/cgi) $

It gave me bad subsitution error, I don't this the value inside the {} will go for interpretation, where your $n will change for its value.

1 Like

Welcome to the forum!

As far as I know, bash doesn't allow such thing as ${dir_$n}.
I'd use array instead:

dir[$a]=someValue;
echo ${dir[$a]} 

Array indices can be strings, too.

To loop through the array (in an arbitrary order!), you'd do:

for d in ${dir[@]} ; do 
  #whatever with $d
done

The variable ${dir[@]} returns the whole array. (same thing ${dir
[*]})

1 Like

Thanks heaps kumaran_5555 and mirni.

I've only just tested what you mentioned which workeda treat!
Now I have to try and utilise it multiple times for multiple variables throughout the script.
I havent yet attempted the array but I might give it a go this week.

Once done I'll post a copy of the finished script as i havent been able to find one similar in the forums.

Thanks again,
Danny.

Back to Post #1. If you really want to do it this way, then you need to use a Shell "eval" statement wherever you are changing the name of an environment variable on the fly. This further involves escaping certain $ symbols to protect them from the Shell first pass.

On a design point it would be much easier to read a flat file of records with each records containing the three parameters. The script would then work for a virtually unlimited number of records.

Hey guys,

Thanks again for your help above, much appreciated.
I'm now trying to use the eval statement as advised above before attempting an array.

Can anyone tell me what i'm doing wrong? I sort of understand the method behind the eval command but haven't been able to use it successfully with the below script...
It should be self explanatory what im trying to acheive, any help would be appreciated. Thanks!

#!/bin/bash

a=/archive
n=1
home=/home/gohara/test

dir_1=/sd1
dir_2=/sd2
dir_3=/sd3

filemask_1=TAV*.???
filemask_2=TAV*.???
filemask_3=TAV*.???

fileage_1=30
fileage_2=30
fileage_3=30

deleteage_1=365
deleteage_2=365
deleteage_3=365


while [ $n -le 3 ]

do

#eval echo '$'dir_$n

eval find $home$dir_$n/$filemask_$n -type f -mtime +$fileage_$n -exec ls {} $home$dir_$n$a \;

n=`expr $n + 1`

done
echo "Script Complete"
eval find '$'home'$'dir_$n/'$'filemask_$n -type f -mtime +'$'fileage_$n -exec ls {} '$'home'$'dir_$n'$'a \;

This will work. You have to use eval to in $dir_$n to replace only $n but keep $dir as it is. after eval you should have statement $dir_1.

That's getting really hairy. It's gonna become an ugly mess of dollar signs and quotes.

Also, using 'eval' can have security implications, when you run 'eval' on something that is not hard-wired (like output of find(1)).

I recommend you look into arrays.

hey legends,
just tested the script with an array (first time for me). check it out;

#!/bin/sh

HOME=/home/gohara/test/
ARCHIVE=archive/
DIRECTORY=( "sd1/" "sd2/" "sd3/")
FILEMASK=( "TAV*.*" "CRM*.*" "FTO*.*" )
ARCHIVETIME=( "30" "60" "90" )
DELETETIME=( "365" "90" "120" )


n=${#DIRECTORY[@]} #num elements in array DIRECTORY
for (( i=0; i<n; i++ ))

do

echo -e "\n!! Moving files older than ${ARCHIVETIME[$i]} days, like ${FILEMASK[$i]} from $HOME${DIRECTORY[$i]} to $HOME${DIRECTORY[$i]}$ARCHIVE...\n"

find $HOME${DIRECTORY[$i]}${FILEMASK[$i]} -type f -mtime +${ARCHIVETIME[$i]} -exec ls {} \;

find $HOME${DIRECTORY[$i]}${FILEMASK[$i]} -type f -mtime +${ARCHIVETIME[$i]} -exec mv {} $HOME${DIRECTORY[$i]}$ARCHIVE  \;

echo -e "\n!! Deleting files older than ${DELETETIME[$i]} days from $HOME${DIRECTORY[$i]}$ARCHIVE\n"

find $HOME${DIRECTORY[$i]}$ARCHIVE${FILEMASK[$i]} -type f -mtime +${DELETETIME[$i]} -exec ls {} \;

find $HOME${DIRECTORY[$i]}$ARCHIVE${FILEMASK[$i]} -type f -mtime +${DELETETIME[$i]} -exec rm {} \;

echo -e "\n!! Archive complete for ${DIRECTORY[$i]}\n\n"

done

echo -e "\n\n!! Script Complete\n"

---------- Post updated at 01:46 PM ---------- Previous update was at 01:45 PM ----------

now i just gotta try retriving the variables from a config file, and outputting all the info to a log file!!

Looks good. Missing a dollar sign here

for (( i=0; i<$n; i++ ))

The two find commands can be put together, one way would be through -ls command of find(1).