Testing a variable inside a for loop

interpretive language scripts


Moderator: Forum moderators

Post Reply
User avatar
wizard
Posts: 2169
Joined: Sun Aug 09, 2020 7:50 pm
Location: Oklahoma, USA
Has thanked: 2980 times
Been thanked: 799 times

Testing a variable inside a for loop

Post by wizard »

The objective is to end the for loop when the variable done = 1, which should happen after 10 seconds, but instead the loop continues, not sure why.

Thanks
wizard

Code: Select all

#! /bin/bash
done=0

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
} &

sleep 10 
done=1
echo $done
echo done=1

Output:

forloop-test.jpg
forloop-test.jpg (12.77 KiB) Viewed 3096 times

Big pile of OLD computers

User avatar
AntonioPt
Posts: 306
Joined: Wed Aug 11, 2021 7:41 pm
Has thanked: 130 times
Been thanked: 55 times

Re: Testing a variable inside a for loop

Post by AntonioPt »

@wizard you forget to increment done :D

((done++))

Code: Select all

#! /bin/bash
done=0

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
        done=1 # set with one or $i
        break
    fi

    echo $i
    sleep 1
    ((done++)) 
} &

sleep 10 

echo $done
echo done=1
wizard wrote: Wed Feb 05, 2025 6:26 pm

The objective is to end the for loop when the variable done = 1, which should happen after 10 seconds, but instead the loop continues, not sure why.

Thanks
wizard

Code: Select all

#! /bin/bash
done=0

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
} &

sleep 10 
done=1
echo $done
echo done=1

Output:
forloop-test.jpg

Why astronauts use Linux
Because you can't open windows in space

User avatar
wizard
Posts: 2169
Joined: Sun Aug 09, 2020 7:50 pm
Location: Oklahoma, USA
Has thanked: 2980 times
Been thanked: 799 times

Re: Testing a variable inside a for loop

Post by wizard »

@AntonioPt

@wizard you forget to increment done

Actually, done is incremented here:

Code: Select all

sleep 10 
done=1

Your code exits the loop in 1 second.

Thanks
wizard

Big pile of OLD computers

User avatar
AntonioPt
Posts: 306
Joined: Wed Aug 11, 2021 7:41 pm
Has thanked: 130 times
Been thanked: 55 times

Re: Testing a variable inside a for loop

Post by AntonioPt »

But @wizard its outside of the loop lol so will never works like you could see :D

Why astronauts use Linux
Because you can't open windows in space

User avatar
wizard
Posts: 2169
Joined: Sun Aug 09, 2020 7:50 pm
Location: Oklahoma, USA
Has thanked: 2980 times
Been thanked: 799 times

Re: Testing a variable inside a for loop

Post by wizard »

@AntonioPt

But @wizard its outside of the loop lol so will never works like you could see

So if the for loop can't read variables outside the loop, then why is this able to stop the loop?

Thanks
wizard

Code: Select all

#! /bin/bash

done=1

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
    
}

Big pile of OLD computers

User avatar
AntonioPt
Posts: 306
Joined: Wed Aug 11, 2021 7:41 pm
Has thanked: 130 times
Been thanked: 55 times

Re: Testing a variable inside a for loop

Post by AntonioPt »

wizard wrote: Wed Feb 05, 2025 8:44 pm

for your example right you wanna test done and it starts with 0 in order to check if done become 1 or you increment done inside the loop or you add done=1 all so inside the loop if done=1 is outside the loop will do what you are asking that is loop 16 times because there is no increment inside loop :D

Code: Select all

done=0 # starting point

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
     break
    fi
    echo $i
    sleep 1
   # done=1 or ((done++))
   # if you add 1
   done=1 # it will stop loop but if you add a different number in the condition will loop 16 times again 
   ((done++)) # and if you add increment it will stop when condition match (any number from 0 till 15 ) get it ? 
}

Why astronauts use Linux
Because you can't open windows in space

User avatar
AntonioPt
Posts: 306
Joined: Wed Aug 11, 2021 7:41 pm
Has thanked: 130 times
Been thanked: 55 times

Re: Testing a variable inside a for loop

Post by AntonioPt »

but @wizard you can do some better :)

Code: Select all

start=0  # starting point 
stop=2  # stop loop when it reach 2

# lets loop 16 times
for ((i=0; i<=15; i++)) {
	# let do a echo to see our final result
	echo " i = $i "
	echo " start = $start "
	echo " stop = $stop "
	# now lets check if  start match with stop
	if [ $start == $stop ] ; then 
		break # lets stop loop
	fi
	# lets increment start
	((start++))
}

output would be
i = 0
start = 0
stop = 2
i = 1
start = 1
stop = 2
i = 2
start = 2
stop = 2

Why astronauts use Linux
Because you can't open windows in space

User avatar
AntonioPt
Posts: 306
Joined: Wed Aug 11, 2021 7:41 pm
Has thanked: 130 times
Been thanked: 55 times

Re: Testing a variable inside a for loop

Post by AntonioPt »

sorry @wizard just realize your real question now

so in your first code because you add --> } & <-- when it reach 10 it stops and reads your done=1 and im gonna guess has to do with & and im gonna guess bash will read 10 as 1 and 0 separate and this is why it stops and then continues loop again

but anyways in loops & never should be there and done=1 or ((done++)) it was outside loop there for will never do what you wanna do at the end

Last edited by AntonioPt on Wed Feb 05, 2025 11:19 pm, edited 1 time in total.

Why astronauts use Linux
Because you can't open windows in space

User avatar
rcrsn51
Posts: 1486
Joined: Sun Aug 23, 2020 4:26 pm
Been thanked: 424 times

Re: Testing a variable inside a for loop

Post by rcrsn51 »

I think that you want something like this, using PIDs.

Code: Select all

for ((i=1; i<=15; i++)) { echo $i; sleep 1; } &
PID=$!
sleep 10
kill $PID
User avatar
Trapster
Posts: 228
Joined: Sat Aug 01, 2020 7:44 pm
Location: Texas
Has thanked: 2 times
Been thanked: 71 times

Re: Testing a variable inside a for loop

Post by Trapster »

It seems to work after removing the "&"

Code: Select all

done=0
for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
}

sleep 10 
done=1
echo $done
echo done=1

Code: Select all

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
done=1
/mnt/sda2$ 

EDIT: copy missed the "done=0" at the start of script

Last edited by Trapster on Thu Feb 06, 2025 1:49 am, edited 2 times in total.
User avatar
rcrsn51
Posts: 1486
Joined: Sun Aug 23, 2020 4:26 pm
Been thanked: 424 times

Re: Testing a variable inside a for loop

Post by rcrsn51 »

Trapster wrote: Thu Feb 06, 2025 1:29 am

It seems to work after removing the "&"

Really?

which should happen after 10 seconds, but instead the loop continues

Last edited by rcrsn51 on Thu Feb 06, 2025 1:53 am, edited 1 time in total.
User avatar
Trapster
Posts: 228
Joined: Sat Aug 01, 2020 7:44 pm
Location: Texas
Has thanked: 2 times
Been thanked: 71 times

Re: Testing a variable inside a for loop

Post by Trapster »

See edit to my post

User avatar
Chelsea80
Posts: 389
Joined: Tue Mar 09, 2021 12:44 am
Has thanked: 48 times
Been thanked: 84 times

Re: Testing a variable inside a for loop

Post by Chelsea80 »

@wizard

Bearing in mind I'm only starting out with trying to learn bash script -

So I wonder if this could be adapted to what you want to achieve -

#!/bin/sh

# Define a variable (this could be set dynamically)
my_var="Hello"

# Start a loop (for example, loop through numbers 1 to 5)
for i in {1..5}
do
# Test if the variable is equal to "Hello"
if [ "$my_var" = "Hello" ]; then
echo "The variable my_var is 'Hello' on iteration $i."
else
echo "The variable my_var is not 'Hello' on iteration $i."
fi

# You can change the variable in each loop iteration if needed
my_var="Goodbye"
done

Chelsea80

1. BionicPup32+28 19.03 - Linux 4.9.163 - lxpup - 32-pae [i686] - (UPup Bionic Beaver)
....Frugal Install - Internal HDD - Gateway MX8716b - HDD 120GB - RAM 2GB

2. Friendly-Bionic32 v1.1
....USB Stick 2GB

User avatar
rcrsn51
Posts: 1486
Joined: Sun Aug 23, 2020 4:26 pm
Been thanked: 424 times

Re: Testing a variable inside a for loop

Post by rcrsn51 »

@wizard Are you still interested in understanding why the "done" method fails?

User avatar
wizard
Posts: 2169
Joined: Sun Aug 09, 2020 7:50 pm
Location: Oklahoma, USA
Has thanked: 2980 times
Been thanked: 799 times

Re: Testing a variable inside a for loop

Post by wizard »

@rcrsn51

Are you still interested in understanding why the "done" method fails?

Yes

Do like your code

Code: Select all

for ((i=1; i<=15; i++)) { echo $i; sleep 1; } &
PID=$!
sleep 10
kill $PID

My original code attempts to stop the loop with the if statement inside the loop, yours just kills the process which stops the loop.

Many of the replie above don't follow the intent of the original code which should have been explained better. Pseudo code for it would be something like:
-Start a timer
-Run a process
-Stop the timer when the process is complete

Have not found a good answer for these two cases.

In this case the variable "done" is defined and read from outside the loop and stops the loop.

Code: Select all

#! /bin/bash

done=1

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
    
}

Whereas, if the variable is incremeted after the loop is running it isn't read and does not work.

Code: Select all

#! /bin/bash
done=0

for ((i=1; i<=15; i++)) {
    if [[ $done == 1 ]];then
    break
    fi
    echo $i
    sleep 1
} &

sleep 10 
done=1
echo $done
echo done=1

Thanks
wizard

Big pile of OLD computers

User avatar
rcrsn51
Posts: 1486
Joined: Sun Aug 23, 2020 4:26 pm
Been thanked: 424 times

Re: Testing a variable inside a for loop

Post by rcrsn51 »

You are assuming that the "done" variable acts like a C global variable. You want it to be visible to the background process started by the &. So when the foreground process sets "done=1", the loop in the background would detect this and terminate.

But bash variables don't work that way.

One work-around would be for the foreground to write the value of "done" into a file like "/tmp/done.txt". The background could read the contents of the file each time it goes around the loop and terminate when it detects the change. But that's clearly inefficient.

User avatar
MochiMoppel
Posts: 1343
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 22 times
Been thanked: 521 times

Re: Testing a variable inside a for loop

Post by MochiMoppel »

wizard wrote: Wed Feb 05, 2025 8:44 pm

So if the for loop can't read variables outside the loop, then why is this able to stop the loop?

By using '&' your script started the loop in a subshell.
A subshell inherites values of the parent shell, or better: it makes copies of the variables. This is why the loop knows that done=0 because it was defined before starting the subshell. Once the subshell starts, it cant "see" changes made to the (original) variables of the parent shell.This is why your changes to done=1 is never detected by the subshell. Note that also variables changed in the subshell don't propagate back to the parent shell. This is why in following demo variable i keeps a value of 100 even though the subshell changed the value (of its copy!) to 5.

Code: Select all

#! /bin/sh
done=0
i=100
for ((i=1; i<=5; i++)) {
    echo "Subshell:$done $i"
    sleep 1
} &
done=1	# change value while for loop still running, for loop is unimpressed ;-)
echo "Parent while subshell running:$done $i"
sleep 7
echo "Parent after subshell stopped:$done $i"

Result:

Code: Select all

Parent while subshell running:1 100
Subshell:0 1
Subshell:0 2
Subshell:0 3
Subshell:0 4
Subshell:0 5
Parent after subshell stopped:1 100
User avatar
rcrsn51
Posts: 1486
Joined: Sun Aug 23, 2020 4:26 pm
Been thanked: 424 times

Re: Testing a variable inside a for loop

Post by rcrsn51 »

@MochiMoppel In your above example, why does "done" not need to be exported in order for the background process to initially see it? What is the difference between this situation and a gtkdialog <action> directive where you must export the variables that you want to pass into the environment of the subshell?

There seems to be a distinction between a subprocess and a subshell that I don't understand.

Last edited by rcrsn51 on Thu Feb 06, 2025 3:57 pm, edited 5 times in total.
User avatar
Chelsea80
Posts: 389
Joined: Tue Mar 09, 2021 12:44 am
Has thanked: 48 times
Been thanked: 84 times

Re: Testing a variable inside a for loop

Post by Chelsea80 »

@wizard

-Start a timer
-Run a process
-Stop the timer when the process is complete

OK, this might help (or not) -

#!/bin/bash

# Start the timer
SECONDS=0

# Run your process here
echo "Running your process..."
sleep 10 # Replace this with your actual process

# Stop the timer and calculate elapsed time
duration=$SECONDS
echo "Process completed in $duration seconds."

Chelsea80

1. BionicPup32+28 19.03 - Linux 4.9.163 - lxpup - 32-pae [i686] - (UPup Bionic Beaver)
....Frugal Install - Internal HDD - Gateway MX8716b - HDD 120GB - RAM 2GB

2. Friendly-Bionic32 v1.1
....USB Stick 2GB

User avatar
wizard
Posts: 2169
Joined: Sun Aug 09, 2020 7:50 pm
Location: Oklahoma, USA
Has thanked: 2980 times
Been thanked: 799 times

Re: Testing a variable inside a for loop

Post by wizard »

@rcrsn51
@MochiMoppel

You are assuming that the "done" variable acts like a C global variable. You want it to be visible to the background process started by the &. So when the foreground process sets "done=1", the loop in the background would detect this and terminate.
But bash variables don't work that way.

That explains it, the explanation that the background process/subshell was created by the "&" and its behavior.

One work-around would be for the foreground to write the value of "done" into a file like "/tmp/done.txt". The background could read the contents of the file each time it goes around the loop and terminate when it detects the change

Had already thought of that and it works fine, just wanted to know why it didn't work with a plain bash variable.

Thanks to everyone who replied.
wizard

Big pile of OLD computers

Post Reply

Return to “Scripts”