Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

variable value lost outside of loop 1

Status
Not open for further replies.

Ghodmode

Programmer
Feb 17, 2004
177
NZ
I have a small piece of code that I want to process a list of paths in a configuration file. In the script I'm appending the paths to a variable. Using [tt]echo[/tt] statements, I can see that the variable has the right value inside of the loop, but it loses its value after the loop.

When I use a piece of code that is similar, but doesn't read the configuration file, I don't have the problem.

What am I doing wrong?

Code:
#!/bin/bash
grep -i "^backuppath" backup_config | cut -d: -f2 | tr -d " \t" | while read PATHENTRY; do
    BACKUPPATHS="$BACKUPPATHS $PATHENTRY"
    echo "Backup Paths: $BACKUPPATHS"
done
echo "Backup Paths: $BACKUPPATHS"[/tt]

Output:
Code:
Backup Paths:  /usr/local/mysql
Backup Paths:  /usr/local/mysql /etc/my.cnf
Backup Paths:  /usr/local/mysql /etc/my.cnf /usr/local/apache2
Backup Paths:  /usr/local/mysql /etc/my.cnf /usr/local/apache2 /usr/local/lib/php.ini
Backup Paths:  /usr/local/mysql /etc/my.cnf /usr/local/apache2 /usr/local/lib/php.ini /usr/local/tomcat
Backup Paths:  /usr/local/mysql /etc/my.cnf /usr/local/apache2 /usr/local/lib/php.ini /usr/local/tomcat /usr/lib/oracle/xe/oradata
Backup Paths:

Config file:
Code:
backuppath      :/usr/local/mysql
backuppath      :/etc/my.cnf
backuppath      :/usr/local/apache2
backuppath      :/usr/local/lib/php.ini
backuppath      :/usr/local/tomcat
backuppath      :/usr/lib/oracle/xe/oradata

Thank you.

--
-- Ghodmode

Give a man a fish and he'll come back to buy more... Teach a man to fish and you're out of business.
 
Hi

When something is piped into [tt]while[/tt], it is executed in a subprocess. The environment variables set in the subprocess are discarded together with the subprocess. So after the [tt]while[/tt] the value will not be available anymore.

Rewrite it like this :
Code:
[highlight #eee]#!/bin/bash[/highlight]
[b]while[/b] [b]read[/b] key PATHENTRY; [b]do[/b]
  test [i]"$key"[/i] == [i]"backuppath"[/i] && BACKUPPATHS=[i]"$BACKUPPATHS ${PATHENTRY#:}"[/i]
[b]done[/b] < backup_config
echo [i]"Backup Paths: $BACKUPPATHS"[/i]

Feherke.
 
Thanks for your reply feherke. I should have known about the subprocess :)

With your solution, would it break if there was a space between the colon and the path? In this case would the second variable argument to [tt]read[/tt] contain just the colon before the pattern-matching braces, then append an empty string to the BACKUPPATHS variable?

I actually have a space in most of the entries in that configuration file, but I took it out of the backuppath entries because I wanted to make sure it wouldn't break the code that I was already using.

When this is done, I won't be maintaining the configuration file myself. I wanted to try and anticipate any combination of, or lack of, whitespace characters in the entries.

I also found another solution which doesn't need a loop at all I'll paste it here just in case it might benefit anyone who finds this thread via search:
Code:
BACKUPPATHS=`grep -i "^backuppath" $CONFIGFILE | cut -d: -f2 | tr -d " \t" | tr "\n" " "`

Thank you.

--
-- Ghodmode

Give a man a fish and he'll come back to buy more... Teach a man to fish and you're out of business.
 
Hi

Ghodmode said:
With your solution, would it break if there was a space between the colon and the path? In this case would the second variable argument to read contain just the colon before the pattern-matching braces, then append an empty string to the BACKUPPATHS variable?
No, will not break. The [tt]read[/tt] assigns the input fields to separate variables until there are. Then all the remaining is set to the last variable. So will work, but with an ugliness : the spaces between the colon ( : ) and the path will remain and will appear in the concatenated result string. But that is easy to correct for example with the old [tt]echo[/tt] trick :
Code:
test "$key" == "backuppath" && BACKUPPATHS="$BACKUPPATHS $( echo ${PATHENTRY#:} )"
Ghodmode said:
I also found another solution which doesn't need a loop
Yes, but you use there 4 external commands with 3 pipes run by a subprocess. May not be really efficient.

Well, my above modification also introduces a subprocess, so here is another pure [tt]bash[/tt] way :
Code:
[highlight #eee]#!/usr/bin/bash[/highlight]
[b]while[/b] [b]read[/b] -a str; [b]do[/b]
  test [i]"${str[0]}"[/i] == [i]"backuppath"[/i] && {
    [b]unset[/b] str[0]
    test [i]"${str[1]}"[/i] == [i]":"[/i] && [b]unset[/b] str[1]
    BACKUPPATHS=[i]"$BACKUPPATHS ${str[*]}"[/i]
  }
done < backup_config
echo [i]"Backup Paths: $BACKUPPATHS"[/i]

Feherke.
 
Another way:
Code:
BACKUPPATHS=`awk 'BEGIN{FS="[ \t:]+";ORS=" "}/^backuppath/{print $2}' $CONFIGFILE`

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top