How to listen for, and act upon, a Mac notification using Automator? - macos

Is it possible to listen for a specific notification on Mac and act upon it using Automator?
I regularly use an app that runs a background job then sends a notification when it's finished. The app stays open after the job is finished so I'd like to use Automator to quit the app when the notification is received.
If it's not possible in Automator is there another way I could do this?
More context: the app is actually launched by a Folder Action created using Automator. It detects when a specific SD card is inserted and runs a backup app on that SD card. So maybe there's something I can add to that Folder Action workflow that can detect the notification?

While it's certainly possible to query the sqlite database containing notifications in macOS, it seems to me like an unnecessarily complicated route, and I would first try the following...
In your workflow, add a 'Run Shell Script' action at the end, containing something like this:
while [ $(ps -e | grep "[N]ameOfBackgroundProcess" | wc -l) -gt 0 ]; do
sleep 3
done
killall "NameOfAppToQuit" 1&>2 /dev/null
The while loop checks whether the background job is still running.
ps -e lists all running processes.
grep "[N]ameOf..." gets all lines containing the name. Brackets around the first letter excludes the grep process itself from the output.
wc -l counts the lines.
-gt 0 checks if the number is greater than zero.
When the loop is done, that means the process has exited so we quit the app with killall.
As for the notification route...
I haven't figured everything out, but this might give you a head start:
#!/usr/bin/env bash
# Get the directory of the Notification Center database (works for me in Big Sur):
db_dir=$(lsof -p $(ps aux | grep -m1 usernoted | awk '{ print $2 }')| awk '{ print $NF }' | grep 'db2/db$' | xargs dirname)
# Get the app_id:
app_id=$(sqlite3 "$db_dir"/db 'SELECT app_id FROM app WHERE identifier="com.example.identifier";')
# Get relevant records:
sqlite3 "$db_dir"/db "SELECT * FROM record WHERE app_id='$app_id';"
# And this is where I leave you.
To explore the database in a GUI, try https://sqlitebrowser.org/

Related

grep from screen output and detach

I'm currently writing a bash script which periodically checks for some special words in the server output of a detached screen session, but it enters the session (if grep found something) instead of showing the grepped output. Here is what I've tried:
screen -r foo | grep bar
This gives me the correct return code, but doesn't detach the session afterwards! I also tried && screen -d but that changes nothing.
So how can my script tell me if "bar" is in the output of the server running in my "foo" screen session?
Your problem, I think, is that screen doesn't output in a way that can be searched by grep. If it did, then your attempt at screen -r foo | grep bar && screen -d would likely have been the right way to go about it.
I'd suggest starting the initial screen session with the -L option to enable logging. Then you can search the log file for the value you want.

Mail command executing commands inside of string passed in as message body

Ive got a script that checks if a process is running or not, using ps -ef and some grep. If the process is running, it does nothing. If the process isnt running, it restarts the process, and then sends an email to me stating that the process died.
This script currently runs ever 5 minutes from a admin account's crontab.
Peusdocode + problem code:
#!/bin/sh
# declare a ton of environment variables.
ATONOFVARS=/lots/of/qualified/paths
# declare relevant logging functions
loggingFunction()
# declare failure message to pass into mail (real code)
PAGEMESSAGE="MyServer: process not found in ps -ef. Attempting to Restart... Please check log file in /tmp"
PAGESUBJECT="ProcessHealthCheck.sh - MyServer: process not found in ps -ef"
EMAILLIST="my.email#mycorp.com"
# do the actual check (back to peusdo code)
if [ $(ps -ef | grep process | grep adminAccount | grep -v grep | wc -1) ]
restartProcess()
FAILURE=1
fi
# log the failure and send an email to me (real code)
if [ $FAILURE -eq 1 ]
then
logMsg ""
logMsg "The process is not detected in ps -ef!"
logMsg "Restarting..."
logMsg ""
#send emails out
echo $PAGEMESSAGE | mail -s $PAGESUBJECT $EMAILLIST
fi
To test this, I deliberately killed the PID of my process I want monitored, so this cronjob would have to restart it, I also wanted to test the email capability. The script restarts my process exactly like I want it, and I get the email.
However the email says in the message body: "MyServer: process not found in
the entire listing of ps -ef. Attempting to Restart... Please check log file in /tmp". Also, the addresses that the email was sent to, are lines from ps -ef as well. As in my email had 2000 recipients. Sample addresses: grep#myServer.mydomain.com, process#myServer.mydomain.com
Does anyone know whats going on? Why is mail executing a command that is in a string? Since finding this out, I have changed the string to remove any possibility of a unix command.

The "more" command fails to respond to automated input

I tried to use herestrings to automate a script input and hence wanted to quit "more" of a file in it.
I've used:
$ echo q | more big_file.txt
$ more big_file.txt <<< q
$ yes q | more big_file.txt
$ echo -e "q\n" | more build.txt
but "more" command fails to quit.
Generally, the above mentioned input methods work for other commands in bash, but more seems to be exceptional,
Any idea what makes this a foul attempt?
NOTE: I don't want the data out of "more", but to quit "more" through an automated sequence is the target
When it detects it's running on a terminal, more only takes its input from it. This is so you can run things like:
$ cat multiple_files*.txt | more
(When it's not on a terminal, it doesn't even page, it degrades to behaving like cat.)
Seriously though, whatever your misguided reason for wanting to keep more in the loop is, you're not going to have it quit voluntarily with anything else than terminal input. So:
either you fake it. E.g. with expect
or you have it quit nonvoluntary. With a signal. Try SIGQUIT, move to SIGTERM, fall down to SIGKILL as a last resort.

Script not working with crontab but working when launching it normally

this is my first question on SO, otherwise I generally find what I need.
So here we go, here is my script :
#!/bin/bash
cd /home/laxa/Teeworlds_servers/scripts
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
kill `ps aux | grep -v "grep" | grep "/home/laxa/Teeworlds_servers/" | awk ' { print $2 } '`
and here is my crontab test :
48 23 * * * /home/laxa/Teeworlds_servers/scripts/restart_server.sh > /home/laxa/log.txt 2>&1
So, when I use the script in a bash shell with putty, the script gets executed fine and does it's job.
But when it's executed by the crontab, after some debug, it fails on the kill command.
I tried to set manually the PATH cause it was a big wrong.
Another friend told me to try to debug it, but apparently the script dies directly.
So I am quite blocked now, if someone has an idea or a solution, I would really welcome it.
Thanks.
Ok so, finally I founded that my line was working, but she was returning more processes than intended. And then I discovered that the script was killing himself, so thanks guys !

Checking if user has process running

I have been using this to check if the process i want to edit is already running.
Now this returns if any user has this process running, but since multiple users now run it, i need this line to only return true if the current user has it running. I already have something to execute something as_user and the username is saved in ME.
if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
$LOGNAME provides the current user name. So in case you are using the command to run from X user and want to check for that specific user process, then you can add additional grep for $LOGNAME. I am using SUSE-Linux. In case you are using any other OS, Please specify.

Resources