LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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


Reply
  Search this Thread
Old 10-06-2011, 07:37 AM   #1
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Rep: Reputation: 107Reputation: 107
Question Function goes into infinite loop when reading from a file


Hi All,

I have started to write a small script to add users on remote servers, taking inputs of username, password and groupname interactively.

My intention is to add users one by one on list of servers
OR
to take input from a file like below.

Quote:
user1 user1passwd group1
user2 user2passwd group2
user3 user3passwd group3
My script is working fine when I take details for each user one by one and supply them to my function adduser1
But when I take input from a file (reading line by line), somehow it goes to infinite loop

Please suggest how to take inputs from a file (reading line by line) and supply it to my function adduser1.


Below is my script.
Code:
#!/bin/bash

adduser1 ()
{
userdata="$1"

name=`echo "$userdata" | awk '{print $1}'`
gname=`echo "$userdata" | awk '{print $3}'`

while :
do
 echo
 echo "1. Add user on all servers"
 echo "2. Add user on selected servers"
 echo "3. Exit"
 echo -e -n "\nPlease enter option [1 - 3] :- \c"
 read ans
 case $ans in
  1) echo -e -n "\nAdding user on all servers\n"
     for server in `cat $DIR/serverlist.txt`
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done
     ;;

  2) echo "Enter IP or hostname separated by spaces from all the alive servers"
     read IPlist
     for server in $IPlist
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done
     ;;

  3) break;;

  *) echo "$ans is an invaild option. Please select option 1,2 or 3 only"
     echo "Press [enter] key to continue. . ."
     read enterKey;;
esac
done
}

################################ MAIN
DIR=`pwd`

while :
do
echo
echo "1. Add multiple users from a file"
echo "2. Add users one by one"
echo "3. Exit"
echo -e -n "Please enter option [1 - 3] :- \c"
read ans
case $ans in
  1) echo -e -n "\nYou have to enter all three fields in the file in the below order only.....\t\nUsername\tPassword\tGroupname\n\n"
     sleep 2
     cat /dev/null > $DIR/usertobeadded.txt
     vim $DIR/usertobeadded.txt
     if [ `wc -l $DIR/usertobeadded.txt | awk '{print $1}'` -ne 0 ]
     then
     cat $DIR/usertobeadded.txt | while read userdata
     do
     adduser1 "$userdata"
     done
     else
     echo -e -n "File cannot be empty"
     break
     fi
     ;;

  2) echo -e -n "\nEnter Username, Password and User's primary group separated by spaces (like vikas vikaspasswd l1admin):-\n"
     read userdata
     adduser1 "$userdata"
     ;;

  3) break;;

  *) echo "$ans is an invaild option. Please select option 1,2 or 3 only"
     echo "Press [enter] key to continue. . ."; read enterKey;;
esac
done


This is the output when it works fine (Option 2).
Code:
[root@box1 tmp]# ./test.sh

1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 2

Enter Username, Password and User's primary group separated by spaces (like vikas vikaspasswd l1admin):-
user1 user1passwd group1

1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :- 1

Adding user on all servers
root@192.168.2.20's password:

1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :- 3

1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 3
[root@box1 tmp]#




Below is the output when it goes into infinite loop (Option 1).
Code:
[root@box1 tmp]# ./test.sh

1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 1

You have to enter all three fields in the file in the below order only.....
Username        Password        Groupname


1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :-  is an invaild option. Please select option 1,2 or 3 only
Press [enter] key to continue. . .

1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :-  is an invaild option. Please select option 1,2 or 3 only
Press [enter] key to continue. . .


1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :-  is an invaild option. Please select option 1,2 or 3 only
Press [enter] key to continue. . .

1. Add user on all servers
2. Add user on selected servers
3. Exit


..........  -------------- This goes infinitely, I have trimmed the output to make it readable. 
I have to press Ctrl+C to get out of it.



Please enter option [1 - 3] :-
1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 3
[root@box1 tmp]#

Please suggest.
 
Old 10-06-2011, 09:46 AM   #2
mjones490
Member
 
Registered: Sep 2005
Distribution: LFS
Posts: 60

Rep: Reputation: 22
That break in case 3 is not breaking out of the loop as expected.

Try setting up a flag variable, say "STOP". Set it to 0 or blank. The while loop should check the STOP for 1 or not blank. The in case 3, set the STOP variable to 1 or T or whatever you want to indicate that option 3 was selected. When the while loop wraps around, it will check STOP and exit.
 
Old 10-06-2011, 11:02 AM   #3
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Original Poster
Rep: Reputation: 107Reputation: 107
Unhappy

Quote:
Originally Posted by mjones490 View Post
That break in case 3 is not breaking out of the loop as expected.

Try setting up a flag variable, say "STOP". Set it to 0 or blank. The while loop should check the STOP for 1 or not blank. The in case 3, set the STOP variable to 1 or T or whatever you want to indicate that option 3 was selected. When the while loop wraps around, it will check STOP and exit.
Hi mjones,

I tried setting STOP flag at few places, but nothing worked for me.

Could you please set the flags for me. I have been struggling for this for quite some time now.

This is the latest what I have tried.


This is how I placed, STOP flag.
Code:
#!/bin/bash

adduser1 ()
{
userdata="$1"

name=`echo "$userdata" | awk '{print $1}'`
gname=`echo "$userdata" | awk '{print $3}'`

while :
do

if [ $STOP -eq 0 ]
then
 echo
 echo "1. Add user on all servers"
 echo "2. Add user on selected servers"
 echo "3. Exit"
 echo -e -n "\nPlease enter option [1 - 3] :- \c"
 read ans
 case $ans in
  1) echo -e -n "\nAdding user on all servers\n"
     for server in `cat $DIR/serverlist.txt`
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done
     ;;

  2) echo "Enter IP or hostname separated by spaces from all the alive servers"
     read IPlist
     for server in $IPlist
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done
     ;;

  3) break;;

  *)
     echo "$ans is an invaild option. Please select option 1,2 or 3 only"
     STOP=1
     echo "Press [enter] key to continue. . ."
     read enterKey;;
esac
fi
done
}

################################ MAIN
DIR=`pwd`

STOP=0
while :
do
echo
echo "1. Add multiple users from a file"
echo "2. Add users one by one"
echo "3. Exit"
echo -e -n "Please enter option [1 - 3] :- \c"
read ans
case $ans in
  1) echo -e -n "\nYou have to enter all three fields in the file in the below order only.....\t\nUsername\tPassword\tGroupname\n\n"
     sleep 2
     #cat /dev/null > $DIR/usertobeadded.txt
     vim $DIR/usertobeadded.txt
     if [ `wc -l $DIR/usertobeadded.txt | awk '{print $1}'` -ne 0 ]
     then
     cat $DIR/usertobeadded.txt | while read userdata
     do
     adduser1 "$userdata"
     done
     else
     echo -e -n "File cannot be empty"
     break
     fi
     ;;

  2) echo -e -n "\nEnter Username, Password and User's primary group separated by spaces (like vikas vikaspasswd l1admin):-\n"
     read userdata
     adduser1 "$userdata"
     ;;

  3) break;;

  *) echo "$ans is an invaild option. Please select option 1,2 or 3 only"
     echo "Press [enter] key to continue. . ."; read enterKey;;
esac
done


This is the output of the script.
Quote:
[root@box1 tmp]# ./test.sh

1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 1

You have to enter all three fields in the file in the below order only.....
Username Password Groupname


1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :- is an invaild option. Please select option 1,2 or 3 only
Press [enter] key to continue. . .


Infinite loop stopped, but now it hangs here and does not accepts/identifies any options.

Some options tried by me...
2
2
1
3

Then I had press Ctrl+C



1. Add multiple users from a file
2. Add users one by one
3. Exit
Please enter option [1 - 3] :- 3
[root@box1 tmp]#
 
Old 10-06-2011, 11:29 AM   #4
mjones490
Member
 
Registered: Sep 2005
Distribution: LFS
Posts: 60

Rep: Reputation: 22
Right above your while statements, set the STOP flag to 0. The while statements should check the STOP flag. In case 3 of your switch code, set the STOP flag to 1. Like this:

Code:
STOP=0
while [ $STOP -eq 0 ] :
do
.
.
.
case $ans in
.
.
.
  3) STOP=1
     break;;
.
.
.
esac
done
 
Old 10-06-2011, 11:54 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,968

Rep: Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177
Your issue is not the flags or how you terminate your loops (although personally I try to steer clear of creating infinite loops as you have for this exact reason),
but rather that the read in the function has no scope and hence is reading from the same file as the read in your first while loop.

The clue is in your output:
Code:
1. Add user on all servers
2. Add user on selected servers
3. Exit

Please enter option [1 - 3] :- is an invaild option. Please select option 1,2 or 3 only
Press [enter] key to continue. . .
The red portion is your own code which shows you that the case statement has been entered and invalid input has been given.
Try adding an echo to the default clause of the case:
Code:
echo "$ans"
This will show you what data is being captured and if I am not mistaken it will be from your file.

I would suggest setting up some file descriptors and using read's -u option to read from the appropriate ones.
 
Old 10-06-2011, 01:21 PM   #6
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Original Poster
Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by mjones490 View Post
Right above your while statements, set the STOP flag to 0. The while statements should check the STOP flag. In case 3 of your switch code, set the STOP flag to 1. Like this:

Code:
STOP=0
while [ $STOP -eq 0 ] :
do
.
.
.
case $ans in
.
.
.
  3) STOP=1
     break;;
.
.
.
esac
done
Thanks mjones, for your help. But this did not helped.
 
Old 10-06-2011, 01:30 PM   #7
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Original Poster
Rep: Reputation: 107Reputation: 107
Thumbs up Thanks Grail

Quote:
Originally Posted by grail View Post
I would suggest setting up some file descriptors and using read's -u option to read from the appropriate ones.
Hi Grail,

Many many thanks for your hint.

File descriptors did worked well for me, although I do not have much idea how this worked and what are file descriptors.

This link was a quick help to me.

I must say, I myself would never have thought there was something wrong for my while loop to read the file line by line, as I have used the same loop in many of my scripts.

I am marking this thread as solved.

Below is my working program, it might be useful for others.



Code:
#!/bin/bash

adduser1 ()
{
userdata="$1"

name=`echo "$userdata" | awk '{print $1}'`
gname=`echo "$userdata" | awk '{print $3}'`

echo -e -n "\n\n$userdata\n\n"


#STOP=0
while : #[ $STOP -eq 0 ]
do
 echo
 echo "1. Add user on all servers"
 echo "2. Add user on selected servers"
 echo "3. Exit"
 echo -e -n "\nPlease enter option [1 - 3] :- \c"
 read ans
 echo -e -n  "\n\nValue of ans is $ans\n\n"
 case $ans in
  1) echo -e -n "\nAdding user $name on all servers\n"
     for server in `cat $DIR/serverlist.txt`
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done

     ;;

  2) echo "Enter IP or hostname separated by spaces from all the alive servers"
     read IPlist
     for server in $IPlist
     do
     ssh $server "/usr/sbin/useradd -g $gname $name"
     done
     ;;

  3) break;;

  *)
     echo "$ans is an invaild option. Please select option 1,2 or 3 only"
     echo "Press [enter] key to continue. . ."
     read enterKey;;
esac
done
}

################################ MAIN
DIR=`pwd`

while :
do
echo
echo "1. Add multiple users from a file"
echo "2. Add users one by one"
echo "3. Exit"
echo -e -n "Please enter option [1 - 3] :- \c"
read ans1
case $ans1 in
  1) echo -e -n "\nYou have to enter all three fields in the file in the below order only.....\t\nUsername\tPassword\tGroupname\n\n"
     #sleep 2
     #cat /dev/null > $DIR/usertobeadded.txt
     vim $DIR/usertobeadded.txt
     if [ `wc -l $DIR/usertobeadded.txt | awk '{print $1}'` -ne 0 ]
     then

     exec 3<$DIR/usertobeadded.txt
     while read -u 3 -r userdata
     do
     adduser1 "$userdata"
     done

     else
     echo -e -n "File cannot be empty"
     break
     fi
     ;;

  2) echo -e -n "\nEnter Username, Password and User's primary group separated by spaces (like vikas vikaspasswd l1admin):-\n"
     read userdata
     adduser1 "$userdata"
     ;;

  3) break;;

  *) echo "$ans1 is an invaild option. Please select option 1,2 or 3 only"
     echo "Press [enter] key to continue. . ."; read enterKey;;
esac
done
 
Old 10-07-2011, 05:31 AM   #8
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Original Poster
Rep: Reputation: 107Reputation: 107
Question

Hi Grail,

Using file descriptors with "read -u" option helped me out, but I could not really get how this worked because both the loops yield same output.


Quote:
This worked well for me.
[root@box2 tmp]# cat abc.sh
#!/bin/bash
FILE=/tmp/passwd
exec 3<$FILE
while read -u 3 -r line
do
echo $line
done
[root@box2 tmp]#


This did NOT.
[root@box2 tmp]# cat xyz.sh
FILE=/tmp/passwd
cat $FILE | while read line
do
echo $line
done
[root@box2 tmp]#


[root@box2 tmp]# bash abc.sh
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@box2 tmp]#


[root@box2 tmp]# bash xyz.sh
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@box2 tmp]#
It would be really helpful if you could explain me the difference between two,
or give me some links, I will try to figure out from google-ing around.
 
Old 10-07-2011, 12:40 PM   #9
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,968

Rep: Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177Reputation: 3177
The issue is not about yielding the same results. At a basic level both loops will read the file line by line.
The issue is that you have a second and more read commands in your function and as bash does not scope the read to only
work inside the function it can pull data from any open file descriptor that it knows about. By default all read commands
use the default stdin so irrelevant of where in your code you say the command 'read blah' it will read from stdin and
place whatever it receives into the variable.

If you would like to see the difference with your current examples, you can do the following:
Code:
one_time_read()
{
    read
}

FILE=/tmp/passwd
cat $FILE | while read line
do
    echo $line
    one_time_read
done
Add the same to your other script and see the difference.
 
1 members found this post helpful.
Old 10-08-2011, 01:54 AM   #10
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Original Poster
Rep: Reputation: 107Reputation: 107
Many many thanks Grail.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] infinite loop that isnt infinite? frieza Programming 2 10-27-2010 03:16 PM
Problem with char driver write function - infinite loop Cherubim Linux - Kernel 1 10-13-2009 02:08 AM
Unexpected result in while do done loop reading file steven.c.banks Linux - General 2 05-01-2008 01:32 PM
Infinite Loop ewt3y Programming 3 08-16-2005 10:48 AM
infinite loop beginner_84 Programming 5 08-15-2004 03:32 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:58 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration