LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
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 02-10-2022, 10:25 PM   #1
lqmsh
Member
 
Registered: Oct 2021
Posts: 32

Rep: Reputation: Disabled
restart bash script while loop by itself using signal?


I am trying to get a bash script while loop restart itself using signal properly.
I wrote testing.sh like this below
Code:
#!/bin/bash

function restart {
    $0 "$@"
    exit 0
}
trap restart SIGINT

num=0
while true; do
    echo $num
    ((num=num+1))
    sleep 1s
done
if I run that testing.sh in terminal, as you know it will show incremental number with sleep 1s interval. And if I hit Ctrl+c, the script will restart itself showing the number starting from 0.
Everything seems fine but
Code:
$ pgrep -f testing.sh
shows many PIDs.
Is that a problem?
Because I intended to use it for swaybar status so I can update it by hitting volume control keys, etc.
 
Old 02-10-2022, 10:34 PM   #2
Turbocapitalist
LQ Guru
 
Registered: Apr 2005
Distribution: Linux Mint, Devuan, OpenBSD
Posts: 7,359
Blog Entries: 3

Rep: Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767Reputation: 3767
The way you have it written, the signal causes the script to spawn another process. So each time you interrupt it, there will be yet another script running. If all you wish to do is to reset the counter variable, then have the function do that, and only that:

Code:
#!/bin/bash

function restart {
    num=0
}

trap restart SIGINT

num=0
while true; do
    echo $num
    ((num=num+1))
    sleep 1s
done
What are you trying to do?
 
2 members found this post helpful.
Old 02-10-2022, 10:52 PM   #3
lqmsh
Member
 
Registered: Oct 2021
Posts: 32

Original Poster
Rep: Reputation: Disabled
Quote:
The way you have it written, the signal causes the script to spawn another process.
What I wish to do is to kill itself and start again itself from the beginning.
Showing incremental numbers is just for testing, I will replace it with other command for the status of sway window manager.
 
Old 02-10-2022, 11:33 PM   #4
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,880
Blog Entries: 1

Rep: Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871
Your script cannot commit suicide (other than `exit`), but maybe it can execute itself:
Code:
restart() {
    exec "$myself" "${origargs[@]}"
}
myself="$0"
origargs=("$@")
trap restart INT

Last edited by NevemTeve; 02-10-2022 at 11:35 PM.
 
Old 02-11-2022, 12:22 AM   #5
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
Quote:
Originally Posted by lqmsh View Post
What I wish to do is to kill itself and start again itself from the beginning.
Showing incremental numbers is just for testing, I will replace it with other command for the status of sway window manager.
This looks similar how daemon processes work (= daemon reload/restart), but usually that means you save the pid of the process and later kill and restart it from outside. Do not reinvent the wheel.
 
Old 02-11-2022, 12:55 AM   #6
Mechanikx
Member
 
Registered: Jul 2018
Distribution: Slackware
Posts: 352

Rep: Reputation: 259Reputation: 259Reputation: 259
Here is my dwm status bar script. Maybe you will find it useful.

Code:
#!/bin/bash

update()
{
    kill -SIGTERM $(jobs -p)
}

trap update SIGTERM

let loop=0

while true
do

    if [[ $loop%3600 -eq 0 ]]; then
        weather=$(curl -s wttr.in?format=1 | awk 'FNR == 1 {print $2}')
        let loop=0
    fi

    date=$(date "+%a %b %d %Y %I:%M:%S %P")
    mem=$(free -h | awk 'FNR == 2 {print $7}')
    load=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
    total=$(df -h | awk 'FNR == 4 {print $2}')
    used=$(df -h | awk 'FNR == 4 {print $3}')
    vol=$(amixer | awk 'FNR == 6 {print $5}')
    devs=""

    for device in $(grep '/dev/sd[b-z][1-9]' /proc/mounts | awk '{print $1}' | cut -d '/' -f3)
    do
        devs+=" [$device]= |"
    done

    if [ -z "$devs" ]; then
        status=" $weather | $vol | $load | $used/$total | $mem | $date"
    else        
        status=" $devs $weather | $vol | $load | $used/$total | $mem | $date"
    fi

    xsetroot -name "$status"
    let loop=$loop+1
    sleep 2 &
    wait

done
And here is how I change the volume:

Code:
super + Up
    amixer sset Master 5%+; kill -SIGTERM $(pgrep dwm-status.sh)

super + Down
    amixer sset Master 5%-; kill -SIGTERM $(pgrep dwm-status.sh)

super + Right
    amixer sset Master toggle; kill -SIGTERM $(pgrep dwm-status.sh)
The important part is to background the 'sleep' command then have the status script wait and if the volume is changed to kill the 'sleep' process so the status will be updated in real time.

My bash scripting isn't the greatest so there's probably room for improvement.
 
1 members found this post helpful.
Old 02-11-2022, 01:17 AM   #7
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
Quote:
Originally Posted by Mechanikx View Post
The important part is to background the 'sleep' command then have the status script wait and if the volume is changed to kill the 'sleep' process so the status will be updated in real time.
I don't know how it will work if you send sigterm during the execution of the loop (and "currently" not sleeping).
probably you will find useful: https://askubuntu.com/questions/5757...ng-bash-script
 
1 members found this post helpful.
Old 02-11-2022, 01:39 AM   #8
Mechanikx
Member
 
Registered: Jul 2018
Distribution: Slackware
Posts: 352

Rep: Reputation: 259Reputation: 259Reputation: 259
Quote:
Originally Posted by pan64 View Post
I don't know how it will work if you send sigterm during the execution of the loop (and "currently" not sleeping).
probably you will find useful: https://askubuntu.com/questions/5757...ng-bash-script
Thanks. I will check it out.
 
Old 02-11-2022, 03:52 AM   #9
Mechanikx
Member
 
Registered: Jul 2018
Distribution: Slackware
Posts: 352

Rep: Reputation: 259Reputation: 259Reputation: 259
Quote:
Originally Posted by pan64 View Post
I don't know how it will work if you send sigterm during the execution of the loop (and "currently" not sleeping).
probably you will find useful: https://askubuntu.com/questions/5757...ng-bash-script
I wrote a small script to see what would happen:

Quote:
#!/bin/bash

var='Hello'

update()
{
var='Goodbye'
kill -SIGTERM $(jobs -p)
}

trap update SIGTERM

while true
do
echo $var
done
And this is what happens when it's sent a sigterm:

Code:
...
Hello
Hello
Hello
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Goodbye
Goodbye
Goodbye
...
So kill just errors out with a usage message because $(jobs -p) doesn't return a pid (since there's no background process). Otherwise the script functions as it should.
 
Old 02-11-2022, 04:08 AM   #10
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
Quote:
Originally Posted by Mechanikx View Post
So kill just errors out with a usage message because $(jobs -p) doesn't return a pid (since there's no background process). Otherwise the script functions as it should.
or it will kill a df, awk or other processes.
by the way, you may also try the pkill command:
Code:
kill -SIGTERM $(pgrep dwm-status.sh)
# replace to
pkill -SIGTERM dwm-status.sh
 
Old 02-11-2022, 04:19 AM   #11
Mechanikx
Member
 
Registered: Jul 2018
Distribution: Slackware
Posts: 352

Rep: Reputation: 259Reputation: 259Reputation: 259
Quote:
Originally Posted by pan64 View Post
or it will kill a df, awk or other processes.
by the way, you may also try the pkill command:
Code:
kill -SIGTERM $(pgrep dwm-status.sh)
# replace to
pkill -SIGTERM dwm-status.sh
I don't think I'm getting what you're saying.

Code:
kill -SIGTERM $(pgrep dwm-status.sh)
Sends a sigterm to dwm-status.sh. Which in turn traps that signal and then update() sends a sigterm to any background process launched and in this case, if there is one (might not be sleeping) would be sleep.

I'm unclear as to why this might kill df, awk, or other processes since I'm only killing a bg process and the only one would be sleep.
 
Old 02-11-2022, 04:25 AM   #12
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,041

Rep: Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348Reputation: 7348
I suggested to use a single pkill command instead of kill and pgrep together.

The other kill inside your shell script kill -SIGTERM $(jobs -p) may kill other processes too.
 
Old 02-11-2022, 06:55 AM   #13
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,628

Rep: Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557Reputation: 2557
Quote:
Originally Posted by lqmsh View Post
Because I intended to use it for swaybar status so I can update it by hitting volume control keys, etc.
It seems you should elaborate on this original problem. Sway support key bindings and swaybar appears to have stop/continue behaviour already - so what exactly is it you want to do that needs to be different to the way everyone else is doing it?

 
Old 02-11-2022, 10:54 PM   #14
Mechanikx
Member
 
Registered: Jul 2018
Distribution: Slackware
Posts: 352

Rep: Reputation: 259Reputation: 259Reputation: 259
Quote:
Originally Posted by pan64 View Post
I suggested to use a single pkill command instead of kill and pgrep together.

The other kill inside your shell script kill -SIGTERM $(jobs -p) may kill other processes too.
I took your advice as well as read that SO thread and made some modifications:

Code:
#!/bin/bash

my_pid="$$"

update()
{
    pkill -P "$my_pid" sleep
}

trap update SIGTERM

let loop=0

while true
do

    if [[ $loop%3600 -eq 0 ]]; then
        weather=$(curl -s wttr.in?format=1 | awk 'FNR == 1 {print $2}')
        let loop=0
    fi

    date=$(date "+%a %b %d %Y %I:%M:%S %P")
    mem=$(free -h | awk 'FNR == 2 {print $7}')
    load=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
    total=$(df -h | awk 'FNR == 4 {print $2}')
    used=$(df -h | awk 'FNR == 4 {print $3}')
    vol=$(amixer | awk 'FNR == 6 {print $5}')
    devs=""

    for device in $(grep '/dev/sd[b-z][1-9]' /proc/mounts | awk '{print $1}' | cut -d '/' -f3)
    do
        devs+=" [$device]= |"
    done

    if [ -z "$devs" ]; then
        status=" $weather | $vol | $load | $used/$total | $mem | $date"
    else        
        status=" $devs $weather | $vol | $load | $used/$total | $mem | $date"
    fi

    xsetroot -name "$status"
    let loop=$loop+1
    sleep 2 &
    wait

done
Code:
super + Up
    amixer sset Master 5%+; pkill -SIGTERM dwm-status.sh

...
I believe now there's no ambiguity regarding which process or processes are killed by update().

Thanks again.
 
  


Reply



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
how to loop over text file lines within bash script for loop? johnpaulodonnell Linux - Newbie 9 07-28-2015 03:49 PM
Bash script issue (for loop inside a loop) Mperonen Programming 3 08-08-2013 02:14 AM
[SOLVED] Using while loop & select statement - Loop issues Kustom42 Programming 4 05-17-2013 08:43 AM
Bash script: restart each instance after it has ended within a loop Jajamd Programming 3 07-01-2012 08:15 PM
[SOLVED] Bash - While Loop reading from two lists simultaneously - nested while loop wolverene13 Programming 11 10-01-2011 05:00 PM

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

All times are GMT -5. The time now is 03:36 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