Bourne Shell - Problem with while loop variable scope.


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Bourne Shell - Problem with while loop variable scope.
# 1  
Old 12-01-2010
Bourne Shell - Problem with while loop variable scope.

Hello

I am having issues with a script I'm working on developing on a Solaris machine.

The script is intended to find out how many times a particular user (by given userid) has logged into the local system for more than one hour today.

Here is my while loop:
Code:
last $user | grep -v 'sshd' | grep -v 'still logged in' | grep "`date | cut -d' ' -f2-4`" | cut -d\( -f2 | cut -d: -f1 | while read numHours
do
        if [ $numHours -gt 0 ]; then
                numLogins=$(( $numLogins + 1 ))
                echo "$user logged in once for more than an hour ($numHours hours)." #DEBUG
        fi
done

I have declared numLogins before the loop, and the problem is after the loop I try and "echo $numLogins" but numLogins always contains 0. Even when my debug line prints out showing that the user has logged in for at least an hour.

I have determined that I believe this is because the while loop (when used in a pipeline) has a seperate variable scope, but I have tried rewriting my loop like:

Code:
while loop=read $line
do
        numHours=`echo $line | grep -v 'sshd' | grep -v 'still logged in' | grep "\`date | cut -d' ' -f2-4`" | cut -d\( -f2 | cut -d: -f1
        if [ $numHours -gt 0 ]; then
                numLogins=$(( $numLogins + 1 ))
                echo "$user logged in once for more than an hour ($numHours hours)." #DEBUG
        fi
done < `last $user`

I also thought it may be with the way I was incrementing my numLogins variable,
I have tried to use:
Code:
(( numLogins++ ))
using expr,
numLogins=`echo $numLogins + 1 | bc`

and a few other methods I can't quite remember.

Any help on this would be extremely appreciated.
Thanks a lot!

Last edited by DaveRich; 12-01-2010 at 05:10 PM..
# 2  
Old 12-01-2010
You can't use read behind a chain of pipes because commands behind pipes will be in a seperate subshell.

When your pipe chain's wider than the screen it's time to rethink what you're doing, anyway. What's the exact output from last and what's the output you want from your program?
# 3  
Old 12-01-2010
My last output is as follows:
Code:
richards  pts/4        s0106002215952e5 Wed Dec  1 14:04   still logged in
richards  sshd         s0106002215952e5 Wed Dec  1 14:04   still logged in
richards  pts/4        s0106002215952e5 Wed Dec  1 12:02 - 13:03  (01:01)
richards  sshd         s0106002215952e5 Wed Dec  1 12:02 - 13:03  (01:01)
richards  pts/3        s0106002215952e5 Tue Nov 30 21:29 - 23:28  (01:58)
richards  sshd         s0106002215952e5 Tue Nov 30 21:29 - 23:28  (01:58)
....

And I would like my program to output (in this case):
Code:
"The user ******** with a user id of *** has logged in 1 time(s) today for over an hour.


Last edited by Scott; 12-01-2010 at 05:36 PM.. Reason: Code tags
# 4  
Old 12-01-2010
Code:
#!/bin/sh

# substitute with last $username > /tmp/$$ on your system
cat > /tmp/$$ <<EOF
richards pts/4 s0106002215952e5 Wed Dec 1 14:04 still logged in
richards sshd s0106002215952e5 Wed Dec 1 14:04 still logged in
richards pts/4 s0106002215952e5 Wed Dec 1 12:02 - 13:03 (01:01)
richards sshd s0106002215952e5 Wed Dec 1 12:02 - 13:03 (01:01)
richards pts/3 s0106002215952e5 Tue Nov 30 21:29 - 23:28 (01:58)
richards sshd s0106002215952e5 Tue Nov 30 21:29 - 23:28 (01:58)
EOF

LOGINS=0
TOTALTIME=0

while read NAME T SESSION DAYNAME MON DAY TIMESTART DASH TIMEEND DURATION
do
	# Don't count SSH sessions
	[ "$T" == "sshd" ] && continue
	# Skip logged-in sessions
	[ "$DASH" == "still" ] && continue

	((LOGINS++))

	DURATION=${DURATION/(/}
	DURATION=${DURATION/)/}
	IFS=":" read HOURS MINS <<< "$DURATION"

	# Turn 05 into 105, so it doesn't think it's octal, ugh
	HOURS="1${HOURS}"
	MINS="1${MINS}"

	(( TOTALTIME += ((HOURS-100)*60)+(MINS-100) ))
done < /tmp/$$

HOURS=$((TOTALTIME/60))
MINS=$((TOTALTIME%60))

if [ "${HOURS}" -ge 1 ]
then
        echo "user logged in ${LOGINS} times for over an hour"
else
        echo "user logged in for ${MINS} minutes"
fi

rm -f /tmp/$$

# 5  
Old 12-01-2010
Would there be anyway to do this without using temporary files?
# 6  
Old 12-01-2010
You might try

Code:
while read ...
do
...
done <<< $(last $user)

if your shell supports it.
# 7  
Old 12-01-2010
Quote:
Originally Posted by Corona688
You might try

Code:
while read ...
do
...
done <<< $(last $user)

if your shell supports it.
What do the 3 <'s mean?

I understand < is redirect, and << is append.
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

Bash Variable scope - while loop while reading from a file

Cope sample1: test.sh i=0 echo " Outside loop i = $i " while do i=$(( $i + 1)) echo "Inside loop i = $i " done echo " Out of loop i is : $i " When run output : Outside loop i = 0 Inside loop i = 1 Inside loop i = 2 Inside loop i = 3 Inside loop i = 4 Inside loop i = 5 Inside... (8 Replies)
Discussion started by: Adarshreddy01
8 Replies

2. Shell Programming and Scripting

For loop in bourne shell is not working

I have a loop with cases I am working on Bourne shell for file in *.${Today}*.csv *.${Today}*.txt\ do case ${file} in sun_detail) do something ;; sum) do something ;; mod) do something ;; *) do something ;; (5 Replies)
Discussion started by: digioleg54
5 Replies

3. Shell Programming and Scripting

Save awk record field in bourne shell variable

Hello, I am trying to write a shell script that maintains the health of the passwd file. The goal is to check for duplicate usernames, UID's etc. I am able to find and sort out the UID and login names via awk (which I would like to use), but I can't figure out how to save the record field into a... (1 Reply)
Discussion started by: Learn4Life
1 Replies

4. Shell Programming and Scripting

Confusion about FOR LOOP syntax between Bourne and BASH shell. Please see.

for (( i=1; i<=3; i++ )); do for (( j=1; j<=3; j++ )); do for (( k=1; k<=3; k++ )); do echo $i$j$k done done done Will the above code work on a BOURNE shell? As far as my understanding is, if I am writing the above code in a file..say lol.sh and then running it through the terminal using... (7 Replies)
Discussion started by: navienavnav
7 Replies

5. Shell Programming and Scripting

Bourne Shell - Dynamic Variable Error

hi, I am trying to assign a value through 'read' and all works well until I have a space in the in putted value, for the life of me I cant figure out how to escape this. :wall: Any ideas? #!/bin/sh ask_question() { question_text="${1}"; question_answer=""; ... (2 Replies)
Discussion started by: redback
2 Replies

6. Shell Programming and Scripting

Help on "for" loop in bourne shell

Hello Everyone.... I am trying to print a number sequence in following format using for loop. I am using a bourne shell. I tried following for loop condition but it is bash syntax. for (( i=0; i<=5; i++ )) It is giving syntax error. Kindly help with the syntax of "for"... (7 Replies)
Discussion started by: EmbedUX
7 Replies

7. Shell Programming and Scripting

scope of a Variable inside shell script

hi all, i'm using the following script, Status=1 Function_do () { while read line; do if ; then #echo $line if ; then Status=0 echo " LINKINK ERROR " fi fi done < ldd.log } Function_do (4 Replies)
Discussion started by: vij_krr
4 Replies

8. Shell Programming and Scripting

while read loop; scope of variables (shell)

If I set a variable within a while-read loop, sometimes it's local to the loop, sometimes it's global, depending on how the loop is set up. I'm testing this on a Debian Lenny system using both bash and dash with the same results. For example: # Pipe command into while-read loop count= ls -1... (2 Replies)
Discussion started by: mjd_tech
2 Replies

9. Shell Programming and Scripting

problem with shell variable's scope

Hi, I am stuck while developing a shell sub-routine which checks the log file for "success" or "failure". The subroutine reads the log file and checks for key word "success", if found it set the variable (found=1). It returns success or failure based on this variable. My problem is, I can... (2 Replies)
Discussion started by: cjjoy
2 Replies

10. Shell Programming and Scripting

if loop problem in bourne shell

how to use if-loop in bourne shell with multiple conditions like follows if then commands fi it gives me an error test: ] missing then i put if ] it gives me an error [[ not found kindly i need the syntex for the bourne shell (5 Replies)
Discussion started by: ahmad.diab
5 Replies
Login or Register to Ask a Question