Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
|
11-10-2006, 08:47 PM
|
#1
|
|
Member
Registered: Sep 2006
Posts: 79
Rep:
|
How to define a variable In a while loop?
I'm writing a bash package management script and I have a variable, $conflict, that is set to "1" if a system-package conflict exists (the system contains the same files that the package does). Here's the loop where the script checks for conflicts:
Code:
#### CHECK FOR PACKAGE - SYSTEM CONFLICTS
#### Set $conflict to "1" if a conflict exists.
find | \
# Outputs all files and directories under the PWD.
sed "/\.$/d" | \
# Deletes the current directory (.) entry.
sed "s@^.@@" | \
# Removes the "." char from the beginning of all the file paths
while read file ; do
echo 'Entering Loop #1'
#echo "\$file = $file"
sysFile=`echo $file | sed "s@^@$sysRoot@"`
pkgFile=`echo $file | sed "s@^@$pkgPath@"`
#echo '$sysFile =' $sysFile
#echo '$pkgFile =' $pkgFile
if [ -d $pkgFile ] && [ -e $sysFile ] && ! [ -d $sysFile ] ; then
echo "ERROR: $sysFile exists!"
conflict="1"
break
fi
if ! [ -d $pkgFile ] && [ -e $sysFile ] ; then
echo "ERROR: $sysFile exists!"
conflict="1"
break
fi
echo 'Exiting Loop #1'
echo $conflict
done
My problem is that when I set $conflict to "1", it only remains "1" within the loop. Right after the break command, it returns to the default value which I defined at the beginning of the script: "0". How would I make a global change to the variable (meaning that it will = "1" throughout the script)?
Last edited by fatsheep; 11-10-2006 at 08:57 PM.
|
|
|
|
11-10-2006, 09:17 PM
|
#2
|
|
Member
Registered: Sep 2006
Location: Canada
Distribution: Gentoo
Posts: 702
Rep:
|
Shouldn't the
echo $conflict
be outside of the while loop ?
Last edited by dxqcanada; 11-10-2006 at 09:18 PM.
|
|
|
|
11-10-2006, 09:25 PM
|
#3
|
|
Member
Registered: Sep 2006
Posts: 79
Original Poster
Rep:
|
Quote:
|
Originally Posted by dxqcanada
Shouldn't the
echo $conflict
be outside of the while loop ?
|
There's one outside of the loop as well, I just didn't include that segment.
|
|
|
|
11-10-2006, 09:32 PM
|
#4
|
|
Member
Registered: Sep 2006
Location: Canada
Distribution: Gentoo
Posts: 702
Rep:
|
Since you are breaking out of the loop the echo $conflict that is in the loop will show "0" (since conflict only get set to 1 before breaking out of the loop.
The echo $conflict that is outside of the loop should show "1" if the condition is met.
This simple script will show you"
Code:
#!/bin/bash
conflict=0
while read input
do
if [ $input = 0 ]
then
conflict=1
break
fi
echo conflict inside is $conflict
done
echo conflict outside is $confict
|
|
|
|
11-10-2006, 09:33 PM
|
#5
|
|
LQ Newbie
Registered: Nov 2006
Location: san.rr.com
Distribution: Gentoo 2006.0
Posts: 9
Rep:
|
Perhaps try to "define" the variable before the loop?
|
|
|
|
11-10-2006, 09:58 PM
|
#6
|
|
Senior Member
Registered: Oct 2006
Distribution: Slackware 12 Kernel 2.6.24 - probably upgraded by now
Posts: 1,054
Rep:
|
ya I guess, just do conflict=0 before beginning of while loop.
|
|
|
|
11-11-2006, 11:43 AM
|
#7
|
|
Member
Registered: Sep 2006
Posts: 79
Original Poster
Rep:
|
Quote:
|
Originally Posted by dxqcanada
Since you are breaking out of the loop the echo $conflict that is in the loop will show "0" (since conflict only get set to 1 before breaking out of the loop.
The echo $conflict that is outside of the loop should show "1" if the condition is met.
This simple script will show you"
Code:
#!/bin/bash
conflict=0
while read input
do
if [ $input = 0 ]
then
conflict=1
break
fi
echo conflict inside is $conflict
done
echo conflict outside is $confict
|
That example returned errors... Not sure why but here's my edited code:
Code:
#!/bin/bash
# $conflict will be set to "1" if conflict exists
conflict="0"
echo $conflict
sysRoot="/home/ubuntu/Desktop/sources/sysRoot"
rootPkgDir="/home/ubuntu/Desktop/sources/pkg"
pkg="lynx-2.8.6"
pkgPath="$rootPkgDir/$pkg"
#pkgPath="/home/ubuntu/Desktop/sources/pkg/lynx-2.8.6"
echo '$rootPkgDir = ' $rootPkgDir
echo '$pkg = ' $pkg
echo '$pkgPath = ' $pkgPath
cd $pkgPath
#### CHECK FOR PACKAGE - SYSTEM CONFLICTS
#### Set $conflict to "1" if a conflict exists.
find | \
# Outputs all files and directories under the PWD.
sed "/\.$/d" | \
# Deletes the current directory (.) entry.
sed "s@^.@@" | \
# Removes the "." char from the beginning of all the file paths
while read file ; do
#echo 'Entering Loop #1'
#echo "\$file = $file"
sysFile=`echo $file | sed "s@^@$sysRoot@"`
pkgFile=`echo $file | sed "s@^@$pkgPath@"`
#echo '$sysFile =' $sysFile
#echo '$pkgFile =' $pkgFile
if [ -d $pkgFile ] && [ -e $sysFile ] && [ ! -d $sysFile ] ; then
echo "ERROR#1: $sysFile exists."
conflict="1"
echo "Setting \$conflict to \"1\""
echo $conflict
break
fi
if [ ! -d $pkgFile ] && [ -e $sysFile ] ; then
echo "ERROR#2: $sysFile exists."
conflict="1"
echo "Setting \$conflict to \"1\""
echo $conflict
break
fi
#echo 'Exiting Loop #1'
done
echo '$conflict =' $conflict "outside the loop."
Here's the output when I run the script:
Quote:
0
$rootPkgDir = /home/ubuntu/Desktop/sources/pkg
$pkg = lynx-2.8.6
$pkgPath = /home/ubuntu/Desktop/sources/pkg/lynx-2.8.6
ERROR#2: /home/ubuntu/Desktop/sources/sysRoot/usr/bin/lynx exists.
Setting $conflict to "1"
1
$conflict = 0 outside the loop.
|
as you can see, the second if statement evaluates as true ( I have set up a conflict on purpose to test it). Then $conflict is set to "1". I echo conflict inside the if statement, it returns the value "1". Then I issue the break command to exit the loop. Outside the loop, I echo $conflict, this time it evaluates as "0". Why?
|
|
|
|
11-11-2006, 06:39 PM
|
#8
|
|
Member
Registered: Aug 2006
Distribution: slack
Posts: 323
Rep:
|
it seems to me that variable keeps its value within the loop...
try "export $conflict " and echo $conflict ( to see the value)... inside the loop
|
|
|
|
11-11-2006, 06:51 PM
|
#9
|
|
Member
Registered: May 2004
Posts: 552
Rep:
|
The problem is the pipe. When you pipe a new instance of the shell is executed as a separate process to receive data on stdin. When you make a variable assignment inside this new pipe process the variable is lost when the process exits at the end of the pipe.
|
|
|
|
11-11-2006, 07:21 PM
|
#10
|
|
Member
Registered: Aug 2006
Distribution: slack
Posts: 323
Rep:
|
Quote:
|
My problem is that when I set $conflict to "1", it only remains "1" within the loop. Right after the break command, it returns to the default value which I defined at the beginning of the script: "0". How would I make a global change to the variable (meaning that it will = "1" throughout the script)?
|
try declare -r conflict=1
"
-r Make variables read-only. These variables cannot then be assigned values by subsequent assignment statements, nor can they be unset.
"
Last edited by ygloo; 11-11-2006 at 07:22 PM.
|
|
|
|
11-12-2006, 09:24 AM
|
#11
|
|
Member
Registered: May 2004
Posts: 552
Rep:
|
Here's a short example that demonstrates your situation.
Code:
#!/bin/bash
linenum=0
echo -en "hello\nworld\n" | while read x; do
linenum=$((linenum+1))
echo "$linenum: $x"
done
echo "total number of lines = $linenum"
It then prints out...
1: hello
2: world
total number of lines = 0
The problem is you want the total number of lines to be printed as 2. This can not be done with a variable assignment in the loop because the pipe ( | while read ...) runs in a separate process.
|
|
|
|
11-12-2006, 02:36 PM
|
#12
|
|
Member
Registered: Mar 2004
Location: Massachusetts
Distribution: Debian
Posts: 557
Rep:
|
A workaround is to put the entire "stuff | while blah; do halb; done" construct inside backquotes and echo $conflict at the end. i.e.
Code:
conflict=`stuff | ( while blah; do whatever; done; echo $conflict )`
Be sure to echo any errors found inside the subshell to stderr like
Code:
echo >&2 "Oh no Mr. Bill!"
so that they aren't captured by the backquotes
|
|
|
|
03-01-2012, 01:12 AM
|
#13
|
|
LQ Newbie
Registered: Mar 2012
Posts: 1
Rep: 
|
We have the same problem about variable scoping, since I also need to get the presently login user and then, check if corresponding user belongs to a group.
I have wrote several test code with regards to variable scoping outside while loop. But, I could not find any related variable declaration to make the variable value within WHILE loop, I also use export and using extra conditions. The result leads me to conclude that variable within While Loop is only accessible from within the loop itself.
So, I decided to save the value to a file then read it back outside the while loop -- it resolves my problem, please see below code if you could find it useful:
whoami | while read line; do
#if [[ "$userName" = "" ]] ; then
userName=$line
#fi
echo $userName
if [ ! $userName == "" ]; then
echo "userName=$userName" > ~/getuser.bash
break
fi
done
chmod 755 ~/getuser.bash
echo "username value outside while loop=$userName"
if [ -f getuser.bash ] ; then
source getuser.bash
fi
echo "username value outside while loop in getuser.bash file=$userName"
Output:
username value outside while loop=
username value outside while loop in getuser.bash file=hpal
|
|
|
|
03-01-2012, 03:56 PM
|
#14
|
|
Member
Registered: Aug 2009
Distribution: CentOS
Posts: 691
|
@hpal -- You are responding to a thread that is over 5 years old. The OP either solved his problem or gave up long ago.
|
|
|
|
03-02-2012, 10:40 AM
|
#15
|
|
Senior Member
Registered: Mar 2004
Location: england
Distribution: FreeBSD, Debian, Mint, Puppy
Posts: 3,211
Rep: 
|
or dead.
but FYI use export:
Code:
$ export x=fish
$ echo $x
fish
$ while :;do x=chips;break;done
$ echo $x
chips
|
|
|
1 members found this post helpful.
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 06:57 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|