Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
Bash script to toggle between launching and closing program
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Portage & Programming
View previous topic :: View next topic  
Author Message
roytheman
Tux's lil' helper
Tux's lil' helper


Joined: 08 Nov 2009
Posts: 102

PostPosted: Fri Apr 18, 2014 9:32 pm    Post subject: Bash script to toggle between launching and closing program Reply with quote

Hello Gentoo forum,

I am looking for a bash script that I can place on my desktop as an icon, and I want it to start a program, like kcalc, for example (KDE calculator), by clicking on it once and I want it to stop (kill) the calculator when I click on that same icon again. In other words, if I click on the icon once, it starts kcalc, click on it again, it stops kcalc, click on it again, it starts, and so forth. I can already accomplish this with two separate bash script icons on my desktop, one for start only and one for stop only. But I want only one icon that will do both, that will toggle between launching a program and killing the program by clicking on it each time.

I have Googled for one but all I could find were mostly init scripts.

I plan to use this script to stop and start wpa_supplicant (uses pids), click once and I'm online and click again and I offline, click again and I'm online, etc.

I have very little experience with the bash programming language (but I find it quite interesting), and I hope someone might be kind enough to help me find what I am looking for.

Sincerely,
Roy

PS - I found one that looks like it would work with kcalc but it does nothing.

Code:

#!/bin/sh

case "$1" in
start)
   /usr/bin/kcalc
   ;;
stop)
   kill `pgrep -x kcalc'` > /dev/null 2>&1
   ;;
*)
   echo "usage: $0 {start|stop}"
   ;;
esac
Back to top
View user's profile Send private message
cboldt
Veteran
Veteran


Joined: 24 Aug 2005
Posts: 1046

PostPosted: Fri Apr 18, 2014 11:06 pm    Post subject: Reply with quote

Generally, the script is going to be performing a conditional operation.

Code:
if [ test for program_is_running ]; then
  kill_program
  optionally remove the PID file or unset the flag
else
  start_program
  optionally create a PID file or set a flag
fi


There is more than one way to test for program running. I use this in a script to start alpine ...

Code:
if [ -n "`pgrep -u $USER alpine`" ]


The `pgrep -u $USER alpine` command has output if the user running the command has an instance of the program "alpine" running on the system. The "-n" test is met if the sting being testing has non-zero length.

Alternatives would be to test for the presence of a PID file, e.g. in /var/run (not all programs put an entry there, but the script could make one there), and setting a flag in the window-manager. Here is an example of flag-setting using fvwm, no bash scripting is involved in this toggle ...

Code:
DestroyFunc     TOGGLE_STICKY
AddToFunc       TOGGLE_STICKY
+ I Test   (EnvMatch Sticky_Status ON)  Function STOP_STICKY
+ I TestRc (NoMatch)                    Function START_STICKY

DestroyFunc     START_STICKY
AddToFunc       START_STICKY
+ I (do some stuff)
+ I SetEnv Sticky_Status ON

DestroyFunc     STOP_STICKY
AddToFunc       STOP_STICKY
+ I (do some stuff)
+ I SetEnv Sticky_Status OFF
[/code]
Back to top
View user's profile Send private message
roytheman
Tux's lil' helper
Tux's lil' helper


Joined: 08 Nov 2009
Posts: 102

PostPosted: Fri Apr 18, 2014 11:23 pm    Post subject: Reply with quote

Thanks for the reply cboldt,

I'll have to study what you showed me but I found a simple one without pids that works with kcalc :

Code:

#!/bin/sh

# kcalc-toggle

if pgrep -x kcalc > /dev/null; then
   exec killall kcalc
else
   exec kcalc
fi


What do you think of this one?
Back to top
View user's profile Send private message
cboldt
Veteran
Veteran


Joined: 24 Aug 2005
Posts: 1046

PostPosted: Fri Apr 18, 2014 11:38 pm    Post subject: Reply with quote

That would do the job, it's a toggle. It tests for kcalc running, using pgrep. If pgrep returns success (finds kcalc running), then kcalc is killed. Otherwise, kcalc is started.

The "> /dev/null" part stifles the output of pgrep, but the exit status of pgrep ("success" if kcalc is running, "failure" if kcalc is not running) can be tested even though the output is redirected to the bitbucket.

Your other example script needed a parameter to work, like an init script does. The command would have to be "kcalc start" or "kcalc stop", and you want a script that learns or remembers if kcalc is running, not needing to be told "start" or "stop".
Back to top
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Sat Apr 19, 2014 12:04 am    Post subject: Re: Bash script to toggle between launching and closing prog Reply with quote

roytheman wrote:
I plan to use this script to stop and start wpa_supplicant (uses pids), click once and I'm online and click again and I offline, click again and I'm online, etc.

roytheman ... I wouldn't do that (at least in a similar manner to the kcalc script above). Your best to use the /etc/init.d script and check for a exit status of the 'status' ... eg:

Code:
#!/bin/sh

/etc/init.d/net.wlan0 status >/dev/null 2>&1

if [ "$?" -eq 0 ] ; then
   /etc/init.d/net.wlan0 stop
else
   /etc/init.d/net.wlan0 start
fi

... you can check for the 'exit status' of commands like so ...

Code:
# /etc/init.d/net.wlan0 status >/dev/null 2>&1 ; echo $?
0
# /etc/init.d/wpa_supplicant status >/dev/null 2>&1 ; echo $?
3

"0" equates to "success" (meaning a successful exit status) any other number means "failure" (of some sort) in the example above wpa_supplicant returns "3" as the service isn't started.

Really though, you should use a manager (like wpa_gui) for such things ... so I provide the above meerly to explain the scripting involved.

HTH & best ... khay
Back to top
View user's profile Send private message
krinn
Watchman
Watchman


Joined: 02 May 2003
Posts: 7470

PostPosted: Sat Apr 19, 2014 1:09 am    Post subject: Re: Bash script to toggle between launching and closing prog Reply with quote

khayyam wrote:
roytheman wrote:
I plan to use this script to stop and start wpa_supplicant (uses pids), click once and I'm online and click again and I offline, click again and I'm online, etc.

roytheman ... I wouldn't do that (at least in a similar manner to the kcalc script above). Your best to use the /etc/init.d script and check for a exit status of the 'status' ... eg:

Agree with khayyam, because killing a running init script will push it to crash state.
And /etc/init.d/script zap must be done prior to rerun it.

And your one click will be: click->start, click->kill, click->nothing...
Back to top
View user's profile Send private message
roytheman
Tux's lil' helper
Tux's lil' helper


Joined: 08 Nov 2009
Posts: 102

PostPosted: Sat Apr 19, 2014 3:53 pm    Post subject: Reply with quote

Hello again,

You guys have really helped and inspired me in this matter.

khayyam's script works wonderfully for starting the wireless interface but I could not get it to work with a simpler program like kcalc or wpa_gui without it starting another instance of the program each time I clicked on the icon, so I had to use a combination of both scripts posted above for it to start the wireless interface and wpa_gui as shown below:

Code:

#!/bin/sh

sudo /etc/init.d/net.wlp2s0 status > /dev/null 2>&1

if [ "$?" -eq 0 ] ; then
sudo  /etc/init.d/net.wlp2s0 stop
else
sudo  /etc/init.d/net.wlp2s0 start
fi

if pgrep -x wpa_gui > /dev/null; then
   exec killall wpa_gui
else
   exec wpa_gui &
fi


As shown above, I can both launch the wireless interface AND start wpa_gui (the graphical interface) with the first mouse click ,and when I click once again on the icon script, both the wireless interface and wpa_gui closes at the same time. So I can toggle between starting both and closing both at the same time. I like that.

What I would really like is for the scripts to work with the pids. I believe both wpa_gui and the wireless interface have their own pids but they are not directly used in these scripts.

And in order for the script icons to work as a regular user being on the desktop, the suder's file must be edited similar as shown below (for those who might not know that):

Code:

royroy ALL=(root) NOPASSWD: /etc/init.d/net.wlp2s0
royroy ALL=(root) NOPASSWD: /etc/init.d/net.eth0
royroy ALL=(root) NOPASSWD: /dev/null
royroy ALL=(root) NOPASSWD: /usr/sbin/wpa_supplicant




Thank you, cboldt, khayyam, and krinn for help me in this matter.

Best regards,
Roy
Back to top
View user's profile Send private message
mv
Watchman
Watchman


Joined: 20 Apr 2005
Posts: 6747

PostPosted: Sat Apr 19, 2014 4:59 pm    Post subject: Reply with quote

roytheman wrote:
Code:
sudo /etc/init.d/net.wlp2s0 status > /dev/null 2>&1

if [ "$?" -eq 0 ] ; then

Just an editorial comment: You can write this as
Code:
if sudo ... ; then

If you want to store the PID:
Code:

wpa_gui &
wpa_pid=$!
printf '%s' "${wpa_pid}" >/run/wpa.pid

(Note that you must be root to write to that file; see my comments below)
To read the PID:
Code:
if test -r /run/wpd.pid && read -r wpa_pid </runwpa.pid
then kill ... && rm /run/wpd.pid
fi
or use
Code:
tesst -r ... && pkill -F ... && rm ...
Quote:
Code:

royroy ALL=(root) NOPASSWD: /etc/init.d/net.wlp2s0
royroy ALL=(root) NOPASSWD: /etc/init.d/net.eth0
royroy ALL=(root) NOPASSWD: /dev/null
royroy ALL=(root) NOPASSWD: /usr/sbin/wpa_supplicant

This is a horrible idea: It means royroy can start this scripts/tools with any argument! (BTW: what has /dev/null lost here?) For instance, if you start a mail program or browser (as user royroy) which has an exploit, somebody might use this exploit to call wpa_supplicant with appropriate parameters to get some sensitive information!

A better way is to start your whole script with sudo and to allow royroy only to use that script (use sudo or su inside the script to start wpa_supplicant with user permissions instead of root permissions). If you follow this suggestion, you can simply write to /run/wpd.pid as in the above code (otherwise you would need to call a shell with sudo to do the redirection)
Back to top
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Sun Apr 20, 2014 2:24 am    Post subject: Reply with quote

roytheman ...

A couple of comments, firstly, I really don't think this is the proper way to approach this, if you want a method of starting/stopping the network via a click then use some 'manager', because (as mv points to above) your shifting things into a realm where you're executing things as superuser when there is no need to. For example, wpa_supplicant has a method of allowing users access to the ctrl_interface and so the wpa_supplicant process, by using this no escalation of privileges is required, and wpa_gui can be used to start/stop the network (which, incidentally, doesn't need to be killed and restarted when the network is brought up/down). To do this all you need do is allow the user access to the ctrl_interface ...

/etc/wpa_supplicant/wpa_supplicant.conf
Code:
ctrl_interface=DIR=/run/wpa_supplicant GROUP=wheel
update_config=1

... here to group 'wheel' is used (which I assume your user is in) but a separate group could be created if need be.

Secondly, in the script above you're starting/stopping net.wlan0 (as per my example) but this will also start/stop anything dependent on 'net'. Really, all that is needed is that wpa_supplicant connect/disconnect (which due to /etc/wpa_supplicant/wpa_cli) will call /etc/init.d/net.wlan0 (and so have dhcpcd started, etc). So, using the method provided by wpa_supplicant is far better in this regard as all the process/PID checking is done ... and you have wpa_gui as your means of control.

Thirdly, the use of 'sudo' for such things should be avoided ... as I explained above there is no privilege escalation required, and as mv pointed out its an abuse (indeed dangerous) to allow any more escalation of privileges than is required. I see (or have seen) all manner of scripts and instructions (normally with the word 'ubuntu' attached) where every command is prefaced with sudo ... its a bad habit and should be checked ... if not avoided altogether (such as in scripts!).

So, though you have based the above on the information I provided, I should note that I did state that this was given to show you what was involved, but I didn't (and don't) recommend this.

best ... khay
Back to top
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Sun Apr 20, 2014 1:31 pm    Post subject: Reply with quote

roytheman ...

An afterthought: I think something more along these lines would be better ...

Code:
#!/bin/sh

wpa_cli ping >/dev/null 2>&1

if [ "$?" -gt 0 ]; then
    # we do nothing as wpa_supplicant isn't running
    exit
fi

status=`wpa_cli status |awk -F= '/^wpa_state/{v=1; if ($2 == "COMPLETED") v=0; print v}'`

if [ $status -eq 0 ]; then
    wpa_cli disconnect
else
    wpa_cli reconnect
fi

It requires that net.wlan0 be started, but once started the network would be managed/toggled via the script ... and no sudo is needed (you would of course need to make sure you've configured wpa_supplicant to allow your user access to the ctrl_interface).

Its untested so consider it just an example ... its basically operating much the same as wpa_gui would.

best ... khay
Back to top
View user's profile Send private message
roytheman
Tux's lil' helper
Tux's lil' helper


Joined: 08 Nov 2009
Posts: 102

PostPosted: Mon Apr 21, 2014 2:33 pm    Post subject: Reply with quote

Hello again Gentoo forum,

I configured my scripts a different way that may improve security. I commented out all of the entries in the suder's file (shown below) and I added only one line:

Code:

#royroy ALL=(root) NOPASSWD: /etc/init.d/net.wlp2s0
#royroy ALL=(root) NOPASSWD: /etc/init.d/net.eth0
#royroy ALL=(root) NOPASSWD: /dev/null
#royroy ALL=(root) NOPASSWD: /usr/sbin/wpa_supplicant


Code:

royroy  ALL=(root) NOPASSWD: /usr/bin/wpa-toggle.sh


The script in /usr/bin (wpa-toggle.sh) shown below looks like this:

Code:

#!/bin/sh

# wpa_supplicant-toggle

if #pgrep -x
sudo /etc/init.d/net.wlp2s0 status > /dev/null; then
sudo   /etc/init.d/net.wlp2s0 stop
else
sudo   /etc/init.d/net.wlp2s0 start
fi

if pgrep -x wpa_gui > /dev/null; then
   exec killall wpa_gui
else
   exec wpa_gui &
fi



And the script on my desktop (which executes the above script) looks like this:

Code:

#!/bin/sh

 sudo /usr/bin/wpa-toggle.sh


I had to reboot for the changes to take effect and it works fine.

I realize it may be best to use the intended init scripts in /etc/init.d to start the wired and wireless interfaces but I like clicking once on an icon and it starts and clicking again on that same icon and it stops. It is not that I'm too lazy to use the init scripts, I just like to take advantage of the power of the bash programming language whenever I can.

All the best,
Roy
Back to top
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Mon Apr 21, 2014 7:28 pm    Post subject: Reply with quote

roytheman wrote:
The script in /usr/bin (wpa-toggle.sh) shown below looks like this:

roytheman ... use /usr/local/sbin for this ... /usr/ is for package installed software ...

Code:
#!/bin/sh
# wpa_supplicant-toggle

if /etc/init.d/net.wlp2s0 status >/dev/null 2>&1 ; then
  /etc/init.d/net.wlp2s0 stop
else
  /etc/init.d/net.wlp2s0 start
fi

# don't see why ... but ok
if pgrep -x wpa_gui >/dev/null 2>&1 ; then
  killall wpa_gui
else
  # run as user .. not root
  DISPLAY=":0" ; su -c 'wpa_gui &' royroy
fi

roytheman wrote:
I realize it may be best to use the intended init scripts in /etc/init.d to start the wired and wireless interfaces but I like clicking once on an icon and it starts and clicking again on that same icon and it stops. It is not that I'm too lazy to use the init scripts, I just like to take advantage of the power of the bash programming language whenever I can.

Thats one way of thinking about it ... but I wonder why I bothered with the above.

best ... khay
Back to top
View user's profile Send private message
roytheman
Tux's lil' helper
Tux's lil' helper


Joined: 08 Nov 2009
Posts: 102

PostPosted: Mon Apr 21, 2014 8:34 pm    Post subject: Reply with quote

Hello khayyam,

Please don't be offended due to me failing to read your post thoroughly enough. I can now see you sent considerable time and effort trying to enlighten me on bash scripts. I did try out your wpa_cli script and it did work like you said as long as the wireless interface was already started. But I would like something added to the script to bring the interface down, "like "ifconfig wlp2s0 down" but that would require root access. You see, I've got Gkrellm installed on my desktop which is a system monitor that monitors things such as the interfaces whether they are up or down and also monitors the Internet speed. When I start the wireless interface with the regular init scrips in /etc/init.d, in a root terminal, that interface will appear in Gkrellm and when I stop the wireless interface the same way, that interface in Gkrellm will disappear, making it easy for me to see if I am connected or not. But if I use wpa_cli as in the script you supplied, it will also connect me and disconnect me just fine, but the corresponding interface in Gkrellm stays put instead of disappearing. So please don't feel like what you posted was done in vain. I'm sure I'll come back to it for future reference. I'm still searching for the best method for me.

All the best,
Roy
Back to top
View user's profile Send private message
khayyam
Watchman
Watchman


Joined: 07 Jun 2012
Posts: 6227
Location: Room 101

PostPosted: Tue Apr 22, 2014 1:04 am    Post subject: Reply with quote

roytheman wrote:
Please don't be offended due to me failing to read your post thoroughly enough. I can now see you sent considerable time and effort trying to enlighten me on bash scripts.

roytheman ... honestly, I'm not offended, it was just that after having made suggestions and providing code no reference was made to it, and in some places (namely the 'use of sudo in scripts') that advice was ignored (or ... as you state above ... not read thoroughly enough). I have a general policy that I'll work at a problem until a solution is found ... but if the advice is ignored, or what-have-you, I reserve the right to comment :)

roytheman wrote:
I did try out your wpa_cli script and it did work like you said as long as the wireless interface was already started. But I would like something added to the script to bring the interface down, "like "ifconfig wlp2s0 down" but that would require root access.

... but all of your commands are run as root, you're using sudo to run the script, so that seems like a moot point. wpa_supplicant does require the interface to be marked 'up', and wpa_cli can not be run unless wpa_supplicant is running, so this seems to rule out its use.

roytheman wrote:
You see, I've got Gkrellm installed on my desktop which is a system monitor that monitors things such as the interfaces whether they are up or down and also monitors the Internet speed. When I start the wireless interface with the regular init scrips in /etc/init.d, in a root terminal, that interface will appear in Gkrellm and when I stop the wireless interface the same way, that interface in Gkrellm will disappear, making it easy for me to see if I am connected or not. But if I use wpa_cli as in the script you supplied, it will also connect me and disconnect me just fine, but the corresponding interface in Gkrellm stays put instead of disappearing.

Yes, I see, but I really wonder at the kind of logic involved in this. I have a number of expectations about what a computer should do, the first of these is that any interface allows me to work, and second is that this interfaces doesn't get in the way of that work. If I need to know something (such as network status) I can query it, but otherwise I have no reason to have this present ... and getting "in the way". The reasoning behind this (simple) idea is that such information is something I am generally aware of, I know I'm currently in front of a keyboard, and connected to a network, etc, etc, to have this information represented to me in some manner seems obsolete (and "getting in the way"). I say that not because I'm omnipotent, but because I'm aware of the way in which an interface conditions *use* (and by extension the "design" behind that use). I never ask myself "I wonder if I'm online or not", such a thought never enters into my workflow, it would be a distraction, and the "design" (and use) makes it so. Now, when I read the above I'm somewhat surprised, because (and this is not a judgement of you in any way) the interface seems to be conditioning a certain kind of use (ok, not so much "surprised" as "puzzled").

You mentioned previously the "power of the bash programming language", I was going to comment on it then but didn't as I wasn't sure what to say, something like "with power, comes responsibility" would sound something of a platitude, but really given the mistakes made (and yes, we all make them, so this is not about skill level or what-have-you), I should ask, what power? Because, the power is in how its exercised ... and going back to the above its *use*.

So, drawing those two thoughts together, yes, there is power in (actually /bin/sh ... which is not *supposed* to be bash) shell, but power is not a servant (if that's a suitable analogy) of "use" (ie, all of the "usability" promised by the GUI, etc) but something that comes from it.

best ... khay
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Portage & Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum