1

I have a script which runs differently based on current working directory. Basically it processes an .ini file and takes parameters from it and runs mysql backup.

Script is running as root user.

When I run it with working directory as /root. It exits with error. The .ini file parameters do not reflect in script.

When I do cd / then run it, it works fine.

Here is the function that seems to fail.

get_param()
{

 for line in `cat ${PARAMETERSFILE}`
 do

    if [ "${ISFOUND}" != "true" -a "`echo ${line} | grep ${STAG} | grep -v grep | wc -l`" == "1" ]
   then
     ISFOUND="true"
fi

    if [ "${ISFOUND}" == "true" -a "`echo ${line} | grep ${ETAG} | grep -v grep | wc -l`" == "1" ]
  then
     ISFOUND="false"
fi
if [ "${ISFOUND}" == "true" -a "`echo ${line} | grep ${STAG} | grep -v grep | wc -l`" != "1" ]
   then
    key="`echo ${line} | sed 's/=/ /' | awk '{print $1}'`"
    val="`echo ${line} | sed 's/=/ /' | awk '{print $2}'`"
    cmd="${key}=\"${val}\""
    eval ${cmd}
fi
 done
}

Some variables are as below:

STAG="\[backup\]"
ETAG="\/backup\]"
ISFOUND="false"

ini file is as below

[help]
 backupdir="Backup Home Directory "
 user="MySQL Database  Username"
 password="MySQL Database Password"
 retentioPeriodMinutes="Retention Period of Backup (e.g. 1440= 1 day)"
 memory="Dedicated RAM (Mbyte)"
[/help]

[backup]
 backupdir=/opt/backupdb
 user="root"
 password="xyz"
[/backup]

[restore]
 backupdir=/opt/backupdb
 user="root"
 password="xyz"
 memory="1024"
[/restore]

[houseKeeping]
 backupdir=/opt/backupdb
 retentioPeriodMinutes=10080
[/houseKeeping]

Below is the output while running with sh -xv. It seems pipe is not working as it should when current directory is /root

+ for line in '`cat ${PARAMETERSFILE}`'
echo ${line} | grep ${STAG} | grep -v grep | wc -l
++ grep '\[backup\]'
++ grep -v grep

++ wc -l
+ '[' false '!=' true -a 0 == 1 ']'
echo ${line} | grep ${ETAG} | grep -v grep | wc -l
++ grep '\/backup\]'
++ echo '[help]'
++ grep -v grep
++ wc -l

+ '[' false == true -a 0 == 1 ']'
echo ${line} | grep ${STAG} | grep -v grep | wc -l

++ grep -v grep
++ grep '\[backup\]'
++ echo '[help]'
++ wc -l

Here is same output when working directory is /

+ for line in '`cat ${PARAMETERSFILE}`'
echo ${line} | grep ${STAG} | grep -v grep | wc -l
++ grep '\[backup\]'
++ grep -v grep
++ echo '[help]'

+ '[' false '!=' true -a 0 == 1 ']'
echo ${line} | grep ${ETAG} | grep -v grep | wc -l
++ grep '\/backup\]'

++ grep -v grep
++ wc -l
++ echo '[help]'
+ '[' false == true -a 0 == 1 ']'
echo ${line} | grep ${STAG} | grep -v grep | wc -l
++ echo '[help]'
++ grep -v grep
++ grep '\[backup\]'

++ wc -l
  • You don't show what the value of ${PARAMETERSFILE} is. I'd think that if that is relative to the current directory then that explains a lot. – wurtel Mar 3 '15 at 9:54
  • It is the absolute path of the .ini file. – Anand S Mar 3 '15 at 10:34
  • At least the for line in $(cat $FILE) part will not do what you want, the whole file will be broken up at white space and line will contain each part in turn, i.e. [help], backupdir="Backup, home, etc.... Use while read line; do ... done < $FILE – wurtel Mar 3 '15 at 12:00
  • Why do you need grep -v grep in your pipeline? That's something usually used when grepping the output of ps for a command, because ps will also show the grep process. But why would you need to filter out grep from your init file? Just copying it without understanding it? – Barmar Mar 3 '15 at 21:51
0

I see at least one mistake that could explain the problem. I haven't reviewed your script in detail. Look at what this line does:

  for line in `cat ${PARAMETERSFILE}`
  1. Take the value of the variable PARAMETERSFILE.
  2. Split that value at whitespace — this results in a single word if the value contains only “ordinary” characters.
  3. Perform filename expansion a.k.a. globbing on each word. This still results in a single word if the value of the variable contains only “ordinary” characters.
  4. Run cat on the specified file.
  5. Read the output of cat, since this is a command substitution.
  6. Split the output of the command at whitespace. This time the string to split contains many newlines and a few spaces; the resulting words are [help], backupdir="Backup, Home, Directory, ", user="MySQL, Database, Username", …
  7. Perform filename expansion a.k.a. globbing on each word.

This time some of the words contain wildcards so they will be interpreted as a glob pattern. If the pattern matches no file, it's left as is. If the pattern matches at least one file, it's replaced by the list of matching file.

A string like [help] is a glob pattern that four possible matches one-character filenames: h, e, l, p. So if you run the script in a directory that contains no file by any of these names, the word [help] remains intact, but if e.g. the current directory contains a file called h then [help] is replaced by h.

for line in … does not split the input into lines. The easiest way to do that is

while IFS= read -r line; do
  …
done <"$PARAMETERSFILE"

IFS= read -r line reads exactly one line, with no character other than newline being special. If you want to strip leading and trailing whitespace, remove IFS=. If you want to allow backslash to serve as a line continuation character (i.e. backslash at the end of a line ignores the following newline), remove -r.

  • Thanks for your answer. The script is rather quick and dirty. But I want to know why it executes differently when my current working location is / and not when it is /root. – Anand S Mar 4 '15 at 3:02
  • @AnandS As I explain, this may be because one of them contains a directory that matches one of the patterns like [help] and the other one doesn't. Check what files these directories contain and compare them against the patterns that your broken script expands. – Gilles Mar 4 '15 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.