Waiting for wine to finish running - bash

My current script looks like this:
cd ~/.wine/drive_c/
echo "test123" > foo$$.txt
wine start "C:\foo$$.txt"
wineserver -w
echo "Wine is done!"
which works fine when only one program is running in wine at a time. However if I run this a second time, before the first program is done, both scripts will wait for each others programs to exit.
This does not work:
cd ~/.wine/drive_c/
echo "test123" > foo$$.txt
$(wine start "C:\foo$$.txt") &
wait ${!}
echo "Wine is done!"
as it will exit before you close the text editor.
I need to use the start command, because I want a file to be run with its default editor/viewer.

To wait for the process started by wine to exit, you can pipe its output to another program.
On my system, the following achieves the desired effect:
wine "program.exe" | cat
echo "program.exe has finished"
If you want to wait asynchronously:
wine "program.exe" | cat & pid=$!
# ...
wait $pid
echo "program.exe has finished"

wineserver has a --wait flag which can be used to do exactly that.
However if you run multiple programs at once, it will wait for all of them to finish.

wine <program> waits until the program exits. wine start program does not.
A summary:
wine <program> starts the program and waits until it is finished. I recommend using this method.
wine start <program> starts the program and immediately exits without waiting. The program will keep running in the background.
wine start \wait <program> starts the program and waits until it is finished. This is the same behavior as wine <program>.
wineserver --wait waits until all programs and all services in Wine are finished. This command does not launch any program itself but waits for existing programs and services.
Services like services.exe, plugplay.exe, and winedevice.exe keep on running a few seconds after the last program finishes, and wineserver --wait also waits until these services exit.
Some of these services hold state and write their state (and the registry) to disk when they exit. So if you want to backup or remove your wine prefix, make sure to wait until these services have exited.

What happens is that wine just asks wineserver to start the program and exits, and I have found no good mechanism to get notifications from wineserver about the processes that it spawns.
My suggestion would be to wait for the completion of the process started by wineserver using one of the methods in How to wait for exit of non-children processes, but you need to know its PID. Possible ideas: run wineserver -f -d | grep init_thread( and get PIDs from there, but I can see no easy way to find out which is which, to avoid race conditions, and to ignore noise; or try to find your process in the output of ps, but it's ugly, and definitely not robust.
If nothing better surfaces, you might want to suggest the addition of such a feature to the Wine devs (probably as a flag to wine).

Related

Pause script by keyboard input

(Sorry for my bad english.) I would like to pause a running script by pressing the [SPACE] bar. The script must run, until the user not press the [SPACE] bar, then pause 20 seconds, and run forth. How can i continuously watch the keyboard input while the script is running?
One way to do it:
#!/bin/bash -eu
script(){ #a mock for your script
while :; do
echo working
sleep 1
done
}
set -m #use job control
script & #run it in the background in a separate process group
read -sd ' ' #silently read until a space is read
kill -STOP -$! #stop the background process group
sleep 2 #wait 2 seconds (change it to 20 for your case)
kill -CONT -$! #resume the background process group
fg #put it in the forground so it's killable with Ctrl+C
I think the most simple way is to implement a script with checkpoints, which tests if a pause is required. Of course, it means your code never call 'long' running command...
A more complex solution is to use SIGPAUSE signal. You can have the main process that execute the script and the side process that catches [SPACE] and emit SIGPAUSE to the main process. Here I see at least two issues:
- how to share the terminal/keyboard between the 2 process (simple if your main script don't expect input from keyboard),
- if the main script starts several processes, you will have to deal with process group...
So it really depends on the complexity of your script. You may consider to rely only on regular Job control provided by Bash.
I suggest to use a controlling script that freezes you busy script:
kill -SIGSTOP ${PID}
and then
kill -SIGCONT ${PID}
to allow the process to continue.
see https://superuser.com/questions/485884/can-a-process-be-frozen-temporarily-in-linux for more detailed explanation.

Do not wait for completion before continuing in Makefile

I am looking to launch a debugger program in the background from a Makefile. I want the make call to complete and return and leave the debugger running. It works fine from a shell but when I put it in the Makefile make waits around for all triggered processes to complete.
I have tried the following test target both with and without the -.
sleep:
-sleep 5 &
Regardless, make sits around and waits for sleep to complete.
I do understand that this is not a normal usage of make but it would allow me to present the debugger launcher using the same sort of setup as the build targets.
Have you tried adding an echo "before" before the sleep and an echo "after" after it?
What I think you'll notice is that Make does not wait for sleep 5 & itself to complete, but it waits for all processes started by a target to complete before considering that target to be complete. You will need to spawn a new process -- try nohup <programname> instead of programname &.
The answer to the question I should have asked would be:
sleep:
cygstart sleep 5
Eclipse now considers the build finished immediately.

Running and killing servers and watchers from a bash script

For a webapp I am developing, I have a bash script to watch for changes in the source and update the running environment.
function app-serve {
python runserver.py
}
function compile-coffee {
inotifywait -e modity scripts | while read change; do
coffee -o js scripts
done
}
Now, I need these two functions run simultaneously,
app-serve &
compile-coffee &
And wait, too
wait
The problem is, when I want to stop these processes, a simple Ctrl-C isn't doing it. When I do a Ctrl-C, I get the command prompt back, but the processes run in the functions are still alive.
Is there a way to tell bash to just wait until I hit Ctrl-C, and then kill all the subprocesses?
Edit: One clarification, I see the python process I start in app-serve function is killed. Only the inotifywait and a couple of bash processes are dangling.
You can catch the ctrl-c signal in your bash script and have it execute a function that finds the processes and kills them.
See http://hacktux.com/bash/control/c
Probably something like killall app-server and killall compile-coffee.
Don't forget to exit the bash script with a call to exit.

Bash – How should I idle until I get a signal?

I have a script for launchd to run that starts a server, then tells it to exit gracefully when launchd kills it off (which should be at shutdown). My question: what is the appropriate, idiomatic way to tell the script to idle until it gets the signal? Should I just use a while-true-sleep-1 loop, or is there a better way to do this?
#!/bin/bash
cd "`dirname "$0"`"
trap "./serverctl stop" TERM
./serverctl start
# wait to receive TERM signal.
You can simply use "sleep infinity". If you want to perform more actions on shutdown and don't want to create a function for that, an alternative could be:
#!/bin/bash
sleep infinity & PID=$!
trap "kill $PID" INT TERM
echo starting
# commands to start your services go here
wait
# commands to shutdown your services go here
echo exited
Another alternative to "sleep infinity" (it seems busybox doesn't support it for example) could be "tail -fn0 $0" for example.
A plain wait would be significantly less resource-intensive than a spin lock, even with a sleep in it.
Why would you like to keep your script running? Is there any reason? If you don't do anything later after signal then I do not see a reason for that.
When you get TERM from shutdown then your serverctl and server executable (if there is any) also gets TERM at the same time.
To do this thing by design you have to install your serverctl script as rc script and let init (start and) stop that. Here I described how to set up server process that is not originally designed to work as server.

bash restart sub-process using trap SIGCHLD?

I've seen monitoring programs either in scripts that check process status using 'ps' or 'service status(on Linux)' periodically, or in C/C++ that forks and wait on the process...
I wonder if it is possible to use bash with trap and restart the sub-process when SIGCLD received?
I have tested a basic suite on RedHat Linux with following idea (and certainly it didn't work...)
#!/bin/bash
set -o monitor # can someone explain this? discussion on Internet say this is needed
trap startProcess SIGCHLD
startProcess() {
/path/to/another/bash/script.sh & # the one to restart
while [ 1 ]
do
sleep 60
done
}
startProcess
what the bash script being started just sleep for a few seconds and exit for now.
several issues observed:
when the shell starts in foreground, SIGCHLD will be handled only once. does trap reset signal handling like signal()?
the script and its child seem to be immune to SIGINT, which means they cannot be stopped by ^C
since cannot be closed, I closed the terminal. The script seems to be HUP and many zombie children left.
when run in background, the script caused terminal to die
... anyway, this does not work at all. I have to say I know too little about this topic.
Can someone suggest or give some working examples?
Are there scripts for such use?
how about use wait in bash, then?
Thanks
I can try to answer some of your questions but not all based on what I
know.
The line set -o monitor (or equivalently, set -m) turns on job
control, which is only on by default for interactive shells. This seems
to be required for SIGCHLD to be sent. However, job control is more of
an interactive feature and not really meant to be used in shell scripts
(see also this question).
Also keep in mind this is probably not what you intended to do
because once you enable job control, SIGCHLD will be sent for every
external command that exists (e.g. every time you run ls or grep or
anything, a SIGCHLD will fire when that command completes and your trap
will run).
I suspect the reason the SIGCHLD trap only appears to run once is
because your trap handler contains a foreground infinite loop, so your
script gets stuck in the trap handler. There doesn't seem to be a point
to that loop anyways, so you could simply remove it.
The script's "immunity" to SIGINT seems to be an effect of enabling
job control (the monitor part). My hunch is with job control turned on,
the sub-instance of bash that runs your script no longer terminates
itself in response to a SIGINT but instead passes the SIGINT through to
its foreground child process. In your script, the ^C i.e. SIGINT
simply acts like a continue statement in other programming languages
case, since SIGINT will just kill the currently running sleep 60,
whereupon the while loop will immediately run a new sleep 60.
When I tried running your script and then killing it (from another
terminal), all I ended up with were two stray sleep processes.
Backgrounding that script also kills my shell for me, although
the behavior is not terribly consistent (sometimes it happens
immediately, other times not at all). It seems typing any keys other
than enter causes an EOF to get sent somehow. Even after the terminal
exits the script continues to run in the background. I have no idea
what is going on here.
Being more specific about what you want to accomplish would help. If
you just want a command to run continuously for the lifetime of your
script, you could run an infinite loop in the background, like
while true; do
some-command
echo some-command finished
echo restarting some-command ...
done &
Note the & after the done.
For other tasks, wait is probably a better idea than using job control
in a shell script. Again, it would depend on what exactly you are trying
to do.

Resources