You are not logged in.

#1 2016-04-23 06:09:00

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

how to refresh looping script in bash?

I use the script below for my dwm statusbar:

#! /bin/bash
while true; do

BAT=$(acpi | awk '{print $3, $4, $5}')
DATE=$(date +"%A %F %R")
ESSID=$(iwgetid | awk -F \" '{print $2}')
VOL=$(amixer sget Master | awk -F \[ '/Mono: Playback/ {print $2}' | awk -F \] '{print $1}')
# Keyboard
if [[ $(xset -q | awk '/Group 2/ {print $4}') == "on" ]]; then
        KB="mm"
else
        KB="en"
fi

xsetroot -name "$ESSID | $KB | $VOL | $BAT | $DATE"
sleep 1.5s
done &

In the script, I want to use sleep 10s for not cpu intensive.
But I want to refresh or stop&start that script to immediately update informations on status when I change volume, keyboard and connect to wifi by pressing shortcuts.

I am thinking something like

"amixer set Master +5 unmute && refresh ~/my_dwmstatusbar_script"
XF86AudioRaiseVolume

Is there any idea to do that?
I have googled with no luck.

Offline

#2 2016-04-23 11:28:09

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

Just kill and restart it.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#3 2016-04-23 14:08:22

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,772

Re: how to refresh looping script in bash?

Not an answer to your question, but...   

Why not just decrease the granularity?  The penalty to wake up and go back to sleep is not that bad.
In other words, rather than sleeping for a long time, just take a whole lot of naps.

ewaller@turing/home/ewaller % cat test
#!/usr/bin/bash
for i in $(seq 1 60);
   do
     sleep 1
   done    
ewaller@turing/home/ewaller % time ./test

real	1m0.056s
user	0m0.000s
sys	0m0.013s
ewaller@turing/home/ewaller %    # Edit test in other window...
ewaller@turing/home/ewaller % cat test
#!/usr/bin/bash
for i in $(seq 1 600);
   do
     sleep 0.1
   done    
ewaller@turing/home/ewaller % time ./test

real	1m0.528s
user	0m0.027s
sys	0m0.087s
ewaller@turing/home/ewaller % 

Neither one of those made a dent in my processor load.

Going back to your question.  How are you planning to detect an even while you are sleeping?  I think that something is going to have to send you a signal.

Last edited by ewaller (2016-04-23 14:08:41)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#4 2016-04-23 14:55:28

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

ewaller, doing *nothing* every 10th of a second doesn't put a dent in the cpu load, but doing all those checks on things that rarely change will.

But you can check the volume every second and everything else only once a minte as done here:
https://github.com/Unia/dwmst


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2016-04-23 15:01:24

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,772

Re: how to refresh looping script in bash?

Trilby wrote:

ewaller, doing *nothing* every 10th of a second doesn't put a dent in the cpu load, but doing all those checks on things that rarely change will.

Perhaps.  But you are right, doing time slicing would help.  Low priority stuff only gets checked every 100th trip trough.  High priority stuff every time.  In-between priority, every few trips through the loop.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#6 2016-04-23 21:40:45

Ropid
Member
Registered: 2015-03-09
Posts: 1,069

Re: how to refresh looping script in bash?

You could set up a trap for a signal:

trap 'true' SIGHUP

You could sleep like this:

sleep 10 &
wait

When you now send the bash process that's running your script that HUP signal, the 'wait' will wake up and your script will continue immediately without waiting those 10 seconds.

Downside I see is that there might be a lot of "sleep 10" processes running in parallel if you send the signal a lot. I don't know how to fix that best. The 'wait' will return a 0 status if the sleep finished correctly, but it will return an error status number if it was interrupted by the trapped signal. You could then perhaps do the sleeping part of your script like this, which hopefully works well in killing the sleep process when the refresh signal was sent:

sleep 10 &
if ! wait; then
    kill $(jobs -p)
fi

Last edited by Ropid (2016-04-23 21:42:15)

Offline

#7 2016-04-23 22:12:50

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

You could also just grab the pid of the sleep using the above approach:

sleep 10 &
pid=$!
wait
kill $pid

"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#8 2016-04-24 11:52:54

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

Re: how to refresh looping script in bash?

Urhh, so the script should be like this ?

#! /bin/bash
while true; do

trap 'true' SIGHUP

BAT=$(acpi | awk '{print $3, $4, $5}')
DATE=$(date +"%A %F %R")
ESSID=$(iwgetid | awk -F \" '{print $2}')
VOL=$(amixer sget Master | awk -F \[ '/Mono: Playback/ {print $2}' | awk -F \] '{print $1}')
# Keyboard
if [[ $(xset -q | awk '/Group 2/ {print $4}') == "on" ]]; then
        KB="mm"
else
        KB="en"
fi

xsetroot -name "$ESSID | $KB | $VOL | $BAT | $DATE"
sleep 10s
wait
pid=$1
kill $pid
done &

and send signal from a script I want like this?

#! /bin/bash
amixer set Master 5+ unmute
kill -SIGHUP $(ps -ef | awk '/\/path\/to\/my_dwmstatusbar_script/ {print $2}')

I'm not very smart on writing bash, correct me.

Offline

#9 2016-04-24 13:53:22

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

You have the wait and setting the pid variable in the wrong order and you need to background the sleep or it will not work at all.  I also had a typo in in my post, sorry, it should be `pid=$!`  This sets the variable pid to the return value of the previous command, so it needs to be right after the backgrounded sleep (the shell returns the pid of a process when it is backgrounded).


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#10 2016-04-24 15:36:40

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

Re: how to refresh looping script in bash?

Oh! thanks.
should be like this:

sleep 10 &
pid=$!
wait
kill $pid

it should be `pid=$!`  This sets the variable pid to the return value of the previous command

thanks for explanation.



Now, it works if I change Volume but not if I change keyboard layout.
I set

Option  "XkbOptions"    "grp:alt_shift_toggle"

in /etc/X11/xorg.conf.d/00-keyboard.conf to toggle kb layout.
I don't find way to update the dwmstatusbar script immediately when I toggle my kb layout.

Last edited by duyinthee (2016-04-24 16:02:13)

Offline

#11 2016-04-24 19:21:13

Ropid
Member
Registered: 2015-03-09
Posts: 1,069

Re: how to refresh looping script in bash?

I would do it like this, so that it doesn't try to kill any process if 'sleep 10' ran to its end normally:

sleep 10 &
pid=$!
wait || kill $pid

You can do your signal with 'pkill' instead of doing 'ps' + 'awk' + 'kill':

pkill -HUP -f '^/path/to/my_dwmstatusbar_script'

Offline

#12 2016-04-25 08:56:46

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

Re: how to refresh looping script in bash?

Ropid wrote:

I would do it like this, so that it doesn't try to kill any process if 'sleep 10' ran to its end normally:

sleep 10 &
pid=$!
wait || kill $pid

You can do your signal with 'pkill' instead of doing 'ps' + 'awk' + 'kill':

pkill -HUP -f '^/path/to/my_dwmstatusbar_script'

Thanks...

Last edited by duyinthee (2016-04-25 09:27:41)

Offline

#13 2016-04-26 10:03:38

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

Re: how to refresh looping script in bash?

This script works perfect.

#! /bin/bash
while true; do

trap 'true' SIGHUP

BAT=$(acpi | awk '{print $3, $4, $5}')
DATE=$(date +"%A %F %R")
ESSID=$(iwgetid | awk -F \" '{print $2}')
VOL=$(amixer sget Master | awk -F \[ '/Mono: Playback/ {print $2}' | awk -F \] '{print $1}')
# Keyboard
if [[ $(xset -q | awk '/Group 2/ {print $4}') == "on" ]]; then
        KB="mm"
else
        KB="en"
fi

xsetroot -name "$ESSID | $KB | $VOL | $BAT | $DATE"
sleep 10s &
pid=$1
wait || kill $pid
done &

with

amixer set Master 5+ unmute && pkill -HUP -f /path/to/my_dwmstatusbar_script

in ~/.xbindkeysrc.

But the script will still running after quit dwm using Mod4+Shift+q

If I remove

trap 'true' SIGHUP
.....................
.................
pid=$!
wait || kill $pid

It stops after I quit dwm.

Offline

#14 2016-04-26 11:21:19

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

I'd remove SIGHUP, and use SIGUSR1 (or SIGUSR2) instead.  You've coopted an already used signal which interferes with it's normal function.  Just replace HUP with USR1 in both the trap and pkill commands.

EDIT: actually, I'm not sure if this will work or not.  Probably not as the USR1 will not end the sleep.  An alternative would be to use SIGKILL to kill your script when dwm is exiting.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#15 2016-04-27 19:16:33

Ropid
Member
Registered: 2015-03-09
Posts: 1,069

Re: how to refresh looping script in bash?

I just tried it with USR1, and this works as well. It will also interrupt the 'wait', just like HUP.


duyinthee wrote:

But the script will still running after quit dwm using Mod4+Shift+q

I would look at that '&' you have the very end of your script, after the 'done' of your 'while' loop. Why do you have it there? It might be what keeps things running in the background.

Last edited by Ropid (2016-04-27 19:19:55)

Offline

#16 2016-04-27 20:14:03

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: how to refresh looping script in bash?

The backgrounding ampersand at the end of the loop struck me as odd too, but it would not cause this problem.  Normally people would not backgronud the loop in the script, but instead would background the script when they called it from their xinitrc - but these would have an identical effect.  The problem is/was due to the sighup being ignored.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#17 2016-04-28 15:31:07

duyinthee
Member
Registered: 2015-06-14
Posts: 222
Website

Re: how to refresh looping script in bash?

As a beginner, I put '&' at the very end of the script after 'done' just because of the wiki page's examples.
I have tried the script with '&' and without '&' after 'done'. Both works same and would not cause the problem of the script running after quit dwm.
But I have to put '&' after the script in ~/.xinitrc or it won't work without.

/path/to/my_dwmstatusbar_script &

~/.xinitrc.

And SIGHUP won't work without '&' after 'sleep 5s' too.

Last edited by duyinthee (2016-04-29 09:45:18)

Offline

Board footer

Powered by FluxBB