eval and variable assignment

Hi,

i have an issue with eval and variable assignment.

1) i have a date value in a variable and that date is part of a filename,
var1=20100331
file1=${var1}-D1-0092.xml.zip
file2=${var2}-D2-0092.xml.zip
file3=${var3}-D3-0092.xml.zip
i am passing the above variables to a script via commandline and assigning the values of these
variables to another set of variables using while get opts command as below,

f\) eval FILE=\\$$\{OPTARG\}
	FILES="$FILE $FILES";;

Issue - the array variable FILES is not populated with filenames here.

2) Issue with filenames - I have filenames which consists of spaces and special characters.
eg: REP - inven - 1.TXT
I am using same concept as above. i.e. passing variables to script. i am getting error
with eval command.

Please advise in both scenarios on how to avoid issues.

Thanks in advance..

Regards,
Mohan

Please post the entire script.

To populate an array the correct syntaxes are:

ARRAY=( "Elem1" "Elem 2" "Third element" "Four has index 3" )
# or
ARRAY[$index]="Element X"

Try to put quotes + escaped quotes

eval "FILE=\"\$${OPTARG}\""

Hi Frans,

Thank you very much. First step is working for me.

regarding the step#2, i maintain all the job related variables in a config script which gets evaluated at the start of every job. The below variables are giving error while evaluating,

Var1="REP0022 - Yesterday's account savings_ 1.TXT"

Error :
ksh -: not found

I tried enclosing above filename in single quotes but of no use.

Thanks in advance.

Regards,
Mohan

You should initialize the variable like

STRING="Var1=\"REP0022 - Yesterday's account savings_ 1.TXT\""
eval "$STRING"

HI Frans,

Thank you. I am able to assign the filenames to a variable now . I have 3 variables like this. all of these are assigned to an array. i am able to get part of the filename (i.e. till the space as a value)while retrieving .

Following is the code :

storing the values in FILES string after we receive the values from commandline,
f) eval FILE=\"\$${OPTARG}\"
FILES="$FILE $FILES";;

assigning the FILES string to an array : set -A filesToGet $FILES

Retrieving each file from the array : file=${filesToGet[$curFileIndex]}

but this way it is considering only part of the filename.i.e. till the first space as a first filename. Please suggest how can i retrive the whole filename i.e. REP00029 - Yesterdays Postings Total_ 1.TXT

Once again thanks in advance..

Regards,
Mohan

Maybe you should directly construct the array like this:

# to add $FILE (string) to $FILES (array)
$FILES[${#FILES[@]}]="$FILE" # ${#FILES[@]} gives the nb of elements in the array => the first empty index (first is 0)

Hi Frans,

i am passing 3 variables(which contain filenames) to the script and storing these in a string called FILES. Here FILES is not an array.later i am assigning this string FILES to an array using set -A definition. Please advise on how to retrieve the whole filename at once after i assign the FILES string to an array.

Regards,
Mohan

What i meant is building an array (FilesToGet) in place of a string, so you won't need to use the set -A.
what is the result of ?

for ((i=0; i<${#FilesToGet[@]}; i++))
do
    echo "$i - ${FilesToGet[$i]}"
done

It would be fine if you post the entire script (between code tags!)

Hi Frans,

Please find the code below enclosed between dashed lines.what is a code tag?

-------------------------------------------------

#!/usr/bin/ksh -p
 
 #set -v -x
 
# Source OpUtils environment
eval $(/opt/PROpUtils/default/bin/Prism)
 
# Source gmi environment
eval $(/opt/PRgmi/default/bin/Prism)
 
while getopts p:u:i:l:r:f:c:w:d: name
do
    case $name in
    p)    PROCESSNAME=${OPTARG};;
    u)    eval USERHOST=\$${OPTARG};;
    i)    eval USERID=\$${OPTARG};;
    l)    eval LOCALDIR=\$${OPTARG};;
    r)    eval REMOTEDIR=\$${OPTARG};;
    f)    eval FILE=\"\$${OPTARG}\"
          FILES="\"$FILE\" $FILES";;
    c)    eval COPYPREFIX=\$${OPTARG};;
    w)    eval WAITSECS=\$${OPTARG};;
    d)    eval DURATION=\$${OPTARG};;
    \?)   printf "Usage: %s: [-p process name] [-u user@hostname] [-i userid][-l localdir] [-r remotedir] [-f file(s)] [-c prefix locally] [-w retrywait secs] [-d durat
ion] \n" $0
          exit 2;;
    esac
done
shift $(($OPTIND - 1))
 
echo "Getting Password "
 

 
if [ -f ${LOCALDIR}/../locks/${PROCESSNAME}.lock ] ; then
if kill -0 $(<${LOCALDIR}/../locks/${PROCESSNAME}.lock); then
kill $(<${LOCALDIR}/../locks/${PROCESSNAME}.lock)
fi
fi
 
TMPFILE=/var/tmp/${PROCESSNAME}.tmp
print $$ >${LOCALDIR}/../locks/${PROCESSNAME}.lock
 
print "`date` - Started - Getting $FILES\nremote: $USERHOST:$REMOTEDIR\nlocal: $LOCALDIR\n";
 
set -A filesToGet $FILES
 
totalFiles=${#filesToGet[@]}
 
until [[ ${#filesToGet[@]} -eq 0 ]];do
 
if [ ${TIMEELAPSED} ]
then
   print "`date` - Sleep Time Elapsed: ${TIMEELAPSED}\n"
else
   integer TIMEELAPSED=0
fi
 
if [ $TIMEELAPSED -gt $DURATION ]
then
    print "There were still ${#filesToGet[@]} file(s) to get therefore exiting with exit status 1."
    exit 1
fi
 
curFileIndex=0
 
while [[ $curFileIndex -lt $totalFiles ]];do
 
file=${filesToGet[$curFileIndex]}
 
if [ $file ]
then
        echo In $file if condition
        if [ ! -f ${LOCALDIR}/../locks/${file}.lock ]; then
                print $$ >${LOCALDIR}/../locks/${file}.lock
        fi
 
        echo " $WGET_HOME/wget --no-check-certificate --user=${USERID} --password=${SERVER_PASSWORD} -O ${LOCALDIR}/${file} ${USERHOST}/${REMOTEDIR}/${file}"
$WGET_HOME/wget --no-check-certificate --user=${USERID} --password=${SERVER_PASSWORD} -O ${LOCALDIR}/${file} ${USERHOST}/${REMOTEDIR}/${file}
 
        EXIT_STATUS=$?
        echo "Exit status"$EXIT_STATUS
 
        if [[ $EXIT_STATUS -eq 1 ]]
        then
                echo "`date` - The file $file was not available."
        else
        if [ $EXIT_STATUS -ne 0 ]
        then
                echo "`date` - Wget failed and returned exit code: $EXIT_STATUS"
                exit 2
        else
 
                echo "`date` - Got file ${file}."
                unset filesToGet[$curFileIndex]
 
                if [ $COPYPREFIX ]
                then
                        echo "`date` - Now moving file ${file} to $COPYPREFIX$file"
                        mv ${LOCALDIR}/${file} ${LOCALDIR}/${COPYPREFIX}${file}
                fi
 
         fi
        fi
fi
 
        curFileIndex=$curFileIndex+1
 
        echo Removing lock file
        rm -f ${LOCALDIR}/../locks/${file}.lock
 
done
 
if [[ ${#filesToGet[@]} -ne 0 ]]
then
    if [ $WAITSECS ]
    then
       sleep $WAITSECS
       integer TIMEELAPSED=$TIMEELAPSED+$WAITSECS
    fi
fi
done
print "`date` - **** Finished ****"
 
rm -f ${LOCALDIR}/../locks/${PROCESSNAME}.lock
 
exit 0

--------------------------------------------------

edit by bakunin: after the explanation frans gave you I'm sure you bring your own code-tags to the party, won't you?

For code tags :

  1. select the text you want to be displayed as code
  2. click on the '#' button in toolbar of the editor.

You could replace

f)    eval FILE=\"\$${OPTARG}\"
          FILES="\"$FILE\" $FILES";;

by the following statement

f) eval $FILES[${#FILES[@]}]=\"\\"$OPTARG\\"\"

and in the line

print "`date` - Started - Getting $FILES\nremote:  $USERHOST:$REMOTEDIR\nlocal: $LOCALDIR\n";
# replace $FILES by ${FILES[*]} (to treat $FILES as an array)

Are all the eval statements really necessary ? (for USERHOST, LOCALDIR ...)
couldn't you proceed as for the first parameter like

VARNAME=${OPTARG};;

This won't work in any way: when you store the various elements in a string you have to separate them somehow so that you can later split the string into array elements. Since you said above that your filenames can contain blanks i am at a loss which delimiter character you want to use.

I hope this helps.

bakunin