ProgrammingThis 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.
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.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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)?
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
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."
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?
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.
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.
"
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.
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
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.