5

Is there a option to let a endless while loop, when it's running in background as a function, stop and start running at any given moment with a local variable? I already did try a lot of options, only i was not able to find a neat solution. The only way i could get it working is reading a external text file from within the while loop. And at specified points in the program writing a 0 or 1 to that text file.

What i'm doing now is:

    #!/bin/bash

intr(){ while true                  # function endless while loop start 
        do 
        sleep 0.5                   # execute function every x time
        var1=`grep "1" 0or1.txt`    # read file 0or1.txt 
        if [ -n "$var1" ] ; then    # if text =1 execute function, 
        # do some magic..
        fi
        done
        }                           # end function
        intr &                      # execute function as bg process

#some code                          # located some where in the script
echo "1" > 0or1.txt                 # write 1 to start function 
#some code                          # this should be a local variable??


#some code                          # located some where in the script               
echo "0" > 0or1.txt                 # write 0 to stop function
#some code                          # this should be a local variable??
6
  • 1
    What's your main objective ? To spawn a script which runs indefinitely and stop it at any point ? Also, what is the point of doing intr & when you can put the script itself into background like ./script-name & ? Feb 27, 2016 at 5:06
  • @ serg, the main objective is to let this code functioning as a interrupt. At several points in the program i need to disable the "interrupt" and at several points i need to enable it. (it's not a one time event.) The "intr &" is starting the function, as a background process. If i use this as a foreground function it's not working. (The reason why is still not clear to me.)
    – Underscore
    Feb 27, 2016 at 10:54
  • @serg, executing the program in background is not working because it has a lot of foreground functions. (the above "interrupt code" is needed in 99% of the program.)
    – Underscore
    Feb 27, 2016 at 11:26
  • 1
    @serg, that's exactly what i want. Also at this time i'm not behind my laptop, in evening i will have a extensive look at all the given answers and experiment with them. Anyway thanks all for all the given answers so far.
    – Underscore
    Feb 27, 2016 at 14:09
  • 1
    My answer edited, demo script rewritten. Please review once you have time. Feb 27, 2016 at 15:52

2 Answers 2

2

From the discussion in the comments bellow the question it became apparent that what OP wants is to essentially pause the background function. Quote:

@ serg, the main objective is to let this code functioning as a interrupt. At several points in the program i need to disable the "interrupt" and at several points i need to enable it. (it's not a one time event.)

It is possible to do so with -SIGSTOP and -SIGCONT. These two signals are essentially pause and play buttons of a process. Bellow is modified demo script from what I've originally posted. Essentially , I've spawned function endless as background process, and first send -SIGSTOP and then -SIGCONT to it. The big important point here is that the background process will continue to run even if the main process exits, so in my example bellow the interrupt wouldn't stop outputting to the console, unless I issued kill 1234 form another terminal, where 1234 is the function PID reported from the script. So watch out for that

$ ./someInfiniteLoop.sh                                        
We are in the main, about to spawn the interrupt function
Parent process (the script itself)  7119
Captured 7120
>>>> HEY I'M THE 1 SECOND INTERRUPT
>>>> HEY I'M THE 1 SECOND INTERRUPT
>>>> HEY I'M THE 1 SECOND INTERRUPT
Sending SIGSTOP to  7120
Funciton paused; waiting 3 seconds
You could do something else when function is paused
Function resumed
>>>> HEY I'M THE 1 SECOND INTERRUPT
>>>> HEY I'M THE 1 SECOND INTERRUPT
>>>> HEY I'M THE 1 SECOND INTERRUPT

Demo script source code:

#!/bin/bash
# use the line bellow if you want to silence error messages
# exec 2>/dev/null
endless()
{
  while true
  do

     echo ">>>> HEY I'M THE 1 SECOND INTERRUPT"
  sleep 1
  done
}

echo 'We are in the main, about to spawn the interrupt function'
echo "Parent process (the script itself)  $$"

endless &
endless_pid="$!"
echo "Captured $endless_pid"
sleep 3

echo 'Sending SIGSTOP to ' $endless_pid
kill -SIGSTOP $endless_pid
[ $? -eq 0  ] && echo 'Funciton paused; waiting 3 seconds' || echo 'Something is wrong'

echo 'You could do something else when function is paused'

sleep 3

kill -SIGCONT $endless_pid

[ $? -eq 0   ] && echo 'Function resumed' || echo 'Something is wrong'

sleep 3 && exit 0 

You may wanna read also :


3
  • 1
    thx for the edit! This is working perfect, and also keeps the code short and readable. I'm still working to find something to kill the bg process after exiting, that's no big deal. Anyway thx for the warning, and the useful help.
    – Underscore
    Feb 27, 2016 at 22:12
  • 1
    Well, kill the background process after exiting with kill and give it the PID of that background process. You might wanna save that process ID somewhere , like in a file or use ps to search for the script name. For instance, with ps -ef I can see xieerqi 9590 1899 0 16:31 pts/14 00:00:00 /bin/bash ./someInfiniteLoop.sh Where 9590 is the background process id, same as reported by $! variable Feb 27, 2016 at 23:33
  • Thx for your suggestion. The background process is exiting after i do: kill $$ and then exit the main routine. I did check it with the ps -ef command, which i didn't know before. Very useful.
    – Underscore
    Feb 28, 2016 at 0:32
1

Use the break builtin to stop the while loop.

From help break:

break: break [n]

Exit for, while, or until loops.

Exit a FOR, WHILE or UNTIL loop.  If N is specified, break N enclosing
loops.

Exit Status:
The exit status is 0 unless N is not greater than or equal to 1.

So in your snippet, you can do:

while :; do
    if [ -n "$var1" ] ; then
        break
    fi
done

Or even shorter:

while :; do
    [ -n "$var1" ] && break
done

To pass any input to the function, use positional parameters i.e. arguments. The first argument can be retrieved by $1, second $2 and so on.

For example, if you call function foobar by:

foobar spam

In the function you can use get spam by using $1:

$ foobar () { echo "This is $1" ;}

$ foobar spam
This is spam

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .