I'm creating a Mac Launch Agent for my app. The Launch agent works fine. But the executable bin file prints some console messages,when the exe is started in terminal and all those messages are logged to Mac Console. How can i skip logging those messages to the Mac Console ..?
I have tried adding a shell script as a Lauch Agent, which starts the exe, so that executable won't log messages to the console. But the script doesn't starts the bin.
This is my Launch Agent plist file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.myapp</string>
<key>Program</key>
<string>./bin/MyBin</string>
<key>WorkingDirectory</key>
<string>/Applications/MyApp/</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
You can override the default treatment of stdout and stderr for launchd jobs by adding the StandardOutPath and StandardErrorPath keys to your .plist file. To discard all output, add this:
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
You could also redirect one or both to a log file.
The easiest way is as Gordon Davisson said above. However when i need to start more than one executable, then its possible by shell script.
This was my Script :
#!/bin/bash
cd /Applications/MyApp/
dates=`date`
echo "Exe Started at ::: ${dates}" > proc.log
# Starting Exe
./bin/MyBin 1>/dev/null 2>/dev/null & echo $! > proc.pid
I was having trouble with this script. I can see the proc.log filling up, but no sign of my App. Surprisingly when i removed the '&' from the script ,launch agent started working fine.
./bin/MyBin 1>/dev/null 2>/dev/null & echo $! > proc.pid
Changed to
./bin/MyBin 1>/dev/null 2>/dev/null
I m not sure why Mac is making the background process as a difference in launchd. The Script was & is working fine as it is, when i manually run it.
The output can only be redirected before the process begins. In this case if you don't want to change all your code then the executable for your launch agent will need to be a script. The script can then redirect as needed, e.g.
#!/bin/sh
# redirect to a log file, /dev/null, or wherever it should go;
# this is just an example log file destination
`/usr/bin/dirname $0`/run_real_agent > /tmp/my_agent.$$.log 2>&1
Related
Is there a way to detect if audio is being output from the Mac system? Whether it's via headphone jack, usb-c, or bluetooth, is there a process which runs if and only if audio is playing?
I've made a unix script which plays a 15hz sine waveform, the idea is to execute the script every 580 seconds if and only if no audio is playing. If audio is playing, the script won't execute.
I have really good speakers but the drawback is they enter a 'standby' power saver mode every 10 minutes (600 seconds). When I'm at work I don't really care about whether it runs in the background or not* but when I'm at home I tend to miss notifications when speakers enter standby, so the aim of the script is to play the 3 second waveform every 580 seconds if and only if no audio is playing.
I'm not sure if this is super related to what you want but maybe try out Soundflower ? It's super useful for re-routing audio in mac.
You do not necessarily need to use AppleScript to accomplish the goal, although you certainly can if you want.
I'd opt to use a Launch Agent, as in the following example XML plist code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.my.play.if.no.audio.is.playing</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>[[ $(pmset -g | grep ' sleep') =~ coreaudiod ]] || '/path/to/shell_script'</string>
</array>
<key>RunAtLoad</key>
<false/>
<key>StartInterval</key>
<integer>580</integer>
</dict>
</plist>
Change '/path/to/shell_script' in the XML plist code to the actual fully qualified pathname of your shell script.
Then save is as, e.g., com.my.play.if.no.audio.is.playing.plist in ~/Library/LaunchAgents/ and load it from Terminal using, e.g.:
cd ~/Library/LaunchAgents/
launchctl load com.my.play.if.no.audio.is.playing.plist
Then every 580 seconds your shell script will execute if there is no audio playing.
Notes:
As coded, it assumes the executable bit is set on your shell script.
If you are going to use Launch Agents and Launch Daemons, I highly recommend you read the manual pages for launchctl, launchd.plist and launchd.
You can read the manual page for command in Terminal by typing man command, then press enter, or for easier reading, just type command and then right-click on it and select: Open man Page
To stop your Launch Agent, in Terminal:
cd ~/Library/LaunchAgents/
launchctl unload com.my.play.if.no.audio.is.playing.plist
You could also instead, include the test condition in your shell script, e.g.:
#!/bin/bash
if [[ ! $(pmset -g | grep ' sleep') =~ coreaudiod ]]; then
# Code to generate your sine waveform goes here.
fi
Then, the command used in the example XML plist code would be:
<key>ProgramArguments</key>
<array>
<string>/path/to/shell_script</string>
</array>
If you really want to use AppleScript, and assuming a Stay Open application, then:
Example AppleScript code:
on run
-- # Add any AppleScript code you what run when the
-- # Stay Open AppleScript application is opened.
end run
on idle
do shell script ¬
"[[ $(pmset -g | grep ' sleep') =~ coreaudiod ]] || '/path/to/shell_script'"
return 580
end idle
on quit
continue quit
end quit
Notes:
When saving the example AppleScript code in Script Editor , set File Format: [Application] and [√] Stay open after run handler.
If your add the test condition to your shell script, as shown further above, then your do shell script command would be:
do shell script "'/path/to/shell_script'"
I tend to stay away from using this type of AppleScript application, as I find that over time they can/may become resource intensive in that they continue consume more RAM. YMMV.
I'm setting up a launchdaemon to run a script that checks if a specific local account is logged in. If that account is logged in, it needs to automatically log back out again. I have a working script, but I can't get a launchagent or launchdaemon to run it.
I've tried it as a launchagent, but that doesn't work, and the specific user is specifically blocked from running scripts. This is running on macOS 10.14.5. It sometimes works when launched by our MDM, but we need it to run even if the MDM is unreachable (thus the local script).
This is my agent so far:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>fubar.plist</string>
<key>ProgramArguments</key>
<array>
<string>/location/of/fubar.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>30</integer>
</dict>
</plist>
And this is the script:
currentUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
if [ "$currentUser" == "fubarUser" ]; then
echo "$currentUser is fubarUser. Logging out"
killall loginwindow
fi
I expect it to register that fubarUser has logged in, then echo my message and kill the loginwindow thus logging them out.
If I run the script as root in a terminal window, it correctly identifies whoever is logged in. So I know the script itself works. I just can't get a launchagent or launchdaemon to load it.
In my production version it actually echo's to a log file who it sees is logged in, and that correctly registers the current user.
Turns out it was a permissions problem. We have apparently locked down the permissions on the folder where I was hosting the script. I've since moved it to the /Library/Scripts/ folder and have been able to run it smoothly from there.
MacOS High Sierra
I want to run this script on startup, login and shutdown, logoff.
The script looks like this and is working successfully from terminal:
#!/bin/sh
find /private/my/tmp -mindepth 1 -maxdepth 1 -type d -not -name -specialfolder -exec rm -r {} \;
find /private/my/tmp -mindepth 1 -maxdepth 1 -exec rm -r {} \;
I have used the Automater to create an .app placed my script in Login Items and this works when logging in, however this does not solve the issue of startup, logoff or shutdown so I do not think that this is the answer.
Reading around, it seems I need to use launchd, but I really can't figure out how to do this with my script.
Can anyone please help?
Edit: For using with launchd, how does this look? I am sure to have some mistakes, hopefully someone can guide me in the right direction.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
</dict>
<key>Label</key>
<string>com.startup</string>
<key>Program</key>
<string>/private/myscripts/startup.sh</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>LaunchOnlyOnce</key>
<true/>
</dict>
</plist>
To run the script at both login and logout, you can wrap it in an AppleScript applet.
This AppleScript code will run the script you specify at both startup and termination:
to run_script()
do shell script "/path/to/script.sh"
end run_script
on run
run_script()
end run
on quit
run_script()
continue quit
end quit
Save this in Script Editor.app as an "Application", checking the checkbox labelled "Stay open after run handler". Now, the applet will remain open until manually quit or a logout occurs.
The applet will appear in the Dock; to disable that, add LSUIElement or LSBackgroundOnly keys to the applet's Info.plist. Those are well-documented keys that Google can tell you more about.
Now, finally, we need to make it run at login. You can do this either using Login Items or a launchd plist. Your example plist above should work, provided you point it at the applet's executable in, e.g., App.app/Contents/MacOS/.
i am looking for a way to periodically re-launch an application in OS X. since this application has a GUI i chose the LaunchAgent method to do it. the LaunchAgent will call a shell script, which will quit the application (if running) and then open it again.
so far it works, with the only exception that once my called shell script has ended, the launched GUI application is also quit.
i tried opening the application with trailing "&" and using nohup, but no luck.
this is my LaunchAgent (ignore my stupid StartCalendarInterval settings, they are for debugging only):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.mycompany.myapp_relauncher</string>
<key>ProgramArguments</key>
<array>
<string>/Users/xyz/Desktop/myapp_relauncher.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>21</integer>
<key>Minute</key>
<integer>25</integer>
</dict>
</dict>
</plist>
and this is the called script /Users/xyz/Desktop/myapp_relauncher.sh
#!/bin/bash
function log { echo "myapp: "`date "+%Y%m%d-%H%M%S"`" $1" ; logger -t "myapp" "$1" ; }
# stopping the app if running (code ommitted here)
log "starting application now..."
nohup /Applications/myapp.app/Contents/MacOS/myapp &
log "sleeping a few seconds now..."
sleep 10 # the launched applications stays open
log "done sleeping, quitting."
# script ends, launched application ends too
Add <key>AbandonProcessGroup</key><true/> to your LaunchAgent .plist; without that, when the agent (the script) exits launchd "helpfully" cleans up all leftover subprocesses (technically, anything with the same process group ID), like for example the application.
You want to use disown here. This works without closing the application after the script finishes:
#!/bin/bash
/Applications/Adium.app/Contents/MacOS/Adium &
disown
This is because using & just puts the job into the background. Even though it's in the background it is still a child process of the current script, which is killed when its parent process, the script, finishes. By using disown that relationship is removed and it runs on its own.
You might also just use the open command:
killall myapp; open -jga myapp
open -jg usually opens an application hidden and without raising any windows. If for example TextEdit is open but has no open windows, -jg creates and raises a new default window though. To avoid it, you can test if the application is already open:
<key>ProgramArguments</key>
<array>
<string>bash</string>
<string>-c</string>
<string>pgrep -x TextEdit||open -jga TextEdit</string>
</array>
Hello generous computerists!
So I have a launchd plist item that is calling the below shell script every thirty seconds. It checks to see if a program is running and if it isn't, it restarts it. Or at least that is what it's supposed to do.
The problem is, even when the process has been killed, the shell script is stating that the process is still running. I think this is because somehow the boolean is not being reset (Or something along those lines). Any help?
n=`ps -ef | grep Intel | grep -v grep | wc -l`
if [ $n -gt 0 ]
then
echo `date` CURRENTLY RUNNING. >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
else
echo `date` not running. ATTEMPTING RESTART... >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
cd /Library/LaunchAgents/
launchctl load com.Intel.plist
fi
EDIT 1
It has been suggested that adding a 'Keep Alive' argument may be a good solution to my general problem. Any comments?
Here would be my updated plist file which should guarantee that my app keeps running perpetually:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.Intel</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Library/LaunchAgents/Contents/Intel</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
I would love to hear if people think this is correct or not. Thanks so much!
To troubleshoot the immediate problem, try logging the output of the ps command:
processes=`ps -ef | grep [I]ntel`
if [ -n "$processes" ]
then
echo `date` CURRENTLY RUNNING. "$processes" >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
...
I suspect there's something else running (maybe even the script itself) matching Intel; this'll tell you in the log.
However, I think this is irrelevant, because this script seems to be trying to solve a problem that's better solved elsewhere: launchd is entirely capable of monitoring and restarting the processes it manages (it's one of its significant features). Just add
<key>KeepAlive</key>
<true/>
to /Library/LaunchAgents/com.Intel.plist, and launchd will restart the program itself.
BTW, if you for some reason did need to manually restart a launchd-managed process, launchctl load is the wrong incantation -- you want launchd start.