Wait for background process - macos

I am creating an applescript that should wait for two processes to finish and then execute some logic. The first is an Application, which is easy to wait for.
set program to "Applications/xyz.app"
repeat until (application program is not running)
delay 1
end repeat
Now for my background task that doesn't work since it is a directly called executable not an Application. If it helps the process is aria2. Could anyone tell me how this works, or point me in the right direction to find an answer?

Try using pgrep to look for the process id of a process called aria2 like this:
do shell script "/usr/bin/pgrep aria2"
I don't have aria2 so I am only guessing its process name - try it in the Terminal first to see if it works:
pgrep aria2
There will be no output if it is not running.
To see fuller output, run:
ps -aef | grep -i aria
If you want to check it in a loop, you could do this sort of thing:
set ariarunning to 0
repeat until ariarunning > 0
try
set ariarunning to do shell script "/usr/bin/pgrep aria"
end try
delay 1
end repeat

Related

suspend/resume a process started from ~/.bashrc

I want to start a long-running python process when I log-in to a server.
So I put something like this into ~/.bashrc
python long_running_process.py
This correctly starts the python process on login. The problem here is that I'm not able to suspend it later (with ctrl-z). I can only exit the process by presssing ctrl-c.
I'd like to be able to pause/suspend and resume the python process if possible. This is different from "backgrounding" the process which has been asked and answered here
EDIT: I found a hack that kindof works. I create a dummy shell-script called ~/run.sh and make it executable. Then I put
#!/bin/bash
set -m
python long_running_process.py
in ~/run.sh.
Lastly, I call ~/run.sh in ~/.bashrc instead of starting the python process directly. Giving set -m enables job-control in the script (which is disabled by default for shell-scripts it seems)
This is very hacky. If someone has a nicer/cleaner solution, I'd be very interested in hearing it
You can use POSIX signals, sent with the kill command. I'll run this little Python script that prints its process id and the time once per second, then pause it then resume it:
#!/usr/bin/env python3
import os
import time
while True:
print(f"Process id: {os.getpid()}, time: {int(time.time())}")
time.sleep(1)
It started with process id 63070, so I can pause it with:
kill -STOP 63070
and then resume it with:
kill -CONT 63070
You can stop the process with command kill -SIGSTOP pid where pid is the process id (you can find it with command ps -ef | grep process_name ) and then continue the process with signal SIGCONT.

Crontab closing background process?

I am testing a bash script I hope to run as a cron job to scan a download log and perform labor-intensive conversions on image files. In order to run several conversions at once, the first script loops through the download log and sends the filename to the second script, which I set to run as a background process using &.
The script pair works well, but when the process is complete, I must press the enter key to return to a command prompt. This is a non-issue when I am running a test, but I am not sure if this behavior has ramifications when run as a cron job.
Will this be an issue? If so, is there a way to close the "terminal" running the first script from the crontab?
Here's a truncated form of my code:
Script 1 (to be launched by crontab):
for i in file1 file2 file3 etc
do
bash /path/to/convert.sh $i &
done
exit 0
Script 2 (convert.sh)
fileName=${1?no file given}
jpegName=$(echo $fileName | sed s/tif/jpg/g)
convert $fileName $jpegName
exit 0
Thanks for any help/assurances you can give!
you don't need script 2. you can convert it to function and put it inside script1.
Another problem is you are running convert.sh in an uncontrolled way. You cannot foresee how many processes will be created (background processes) and this may lead to severe performance overheads.
finally, if you cannot end process in normal way, you may choose to terminate it again using cron by issueing pkill script1.sh

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.

How to run a shell script with the terminal closed, and stop the script at any time

What I usually do is pause my script, run it in the background and then disown it like
./script
^Z
bg
disown
However, I would like to be able to cancel my script at any time. If I have a script that runs indefinitely, I would like to be able to cancel it after a few hours or a day or whenever I feel like cancelling it.
Since you are having a bit of trouble following along, let's see if we can keep it simple for you. (this presumes you can write to /tmp, change as required). Let's start your script in the background and create a PID file containing the PID of its process.
$ ./script & echo $! > /tmp/scriptPID
You can check the contents of /tmp/scriptPID
$ cat /tmp/scriptPID
######
Where ###### is the PID number of the running ./script process. You can further confirm with pidof script (which will return the same ######). You can use ps aux | grep script to view the number as well.
When you are ready to kill the ./script process, you simply pass the number (e.g. ######) to kill. You can do that directly with:
$ kill $(</tmp/scriptPID)
(or with the other methods listed in my comment)
You can add rm /tmp/scriptPID to remove the pid file after killing the process.
Look things over and let me know if you have any further questions.

How do I handle stopping my service?

I've turned a program I wrote into a service, and I have a bash script that runs to start up the actual program, since there are things that have to be started in a particular order. The contents of the startup script (called with start-stop-daemon from the init.d script look like :
./rfid_reader &
sleep 2
java ReaderClass &
This works fine, but how do I go about killing them when it comes time to stop the process?
I've seen pidfiles used, do I just get the PIDs of the two programs, write them to a file, and then kill them when it comes time to shut them down, or do I have to ps -ef | grep program to get their PIDs?
I don't think killall is a good idea to do this. You'd better to record the PID of the program started in background in some file(e.g. PID_FILE) and then kill $(<$PID_FILE) to stop it.
Please refer to this thread for how to get the PID the previous started background program.
Assuming you know the name of your program, you can kill them as below :
killall -KILL program_name

Resources