0

I'm creating a launch daemon on my MacBook (with Monterrey installed) to bring back the battery percentage to the lock screen. I was able to craft the following command and run it in the terminal without any issue:

sudo defaults write /Library/Preferences/com.apple.loginwindow.plist LoginwindowText "Battery percentage: `pmset -g batt | perl -pe 's/.*?(\d+\%).*/$1/' | sed -n '2 p'`"

To automate the command (specifically to have it run every minute), I created a file in /Library/LaunchDaemons called com.thecoder.lockscreenbattery.plist with the following markup:

<?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.thecoder.lockscreenbattery</string>

  <key>ProgramArguments</key>
  <array>
    <string>defaults write /Library/Preferences/com.apple.loginwindow.plist LoginwindowText "Battery percentage: `pmset -g batt | perl -pe 's/.*?(\d+\%).*/$1/' | sed -n '2 p'`"</string>
  </array>

  <key>RunAtLoad</key>
  <true/>

  <key>StartInterval</key>
  <integer>60</integer>
</dict>
</plist>

Finally, to start the daemon, I ran the Terminal command sudo launchctl load /Library/LaunchDaemons/com.thecoder.lockscreenbattery.plist (I also made sure that the file had execute permissions for the user, group, and others).

However, the command does not run like it's supposed to every minute. In fact, it only runs when I explicitly run it in the Terminal. Does anyone have any ideas for how I can continue troubleshooting this? Thank you so much in advance!

1 Answer 1

2

The elements of ProgramArguments must be the program to run (as a single <string>), followed by the arguments to pass to it (each as a separate <string>). You're trying to put in a shell command line, with multiple programs, pipes, quoting, etc -- none of which are supported here.

Either put the shell code in a shell script (and put the path to the script as the single element of ProgramArguments), or pass it to bash with the -c option, and let that parse it:

  <key>ProgramArguments</key>
  <array>
    <string>bash</string>
    <string>-c</string>
    <string>defaults write /Library/Preferences/com.apple.loginwindow.plist LoginwindowText "Battery percentage: `pmset -g batt | perl -pe 's/.*?(\d+\%).*/$1/' | sed -n '2 p'`"</string>
  </array>

BTW, when troubleshooting launchd jobs, it's often useful to capture output & error messages from the job with the StandardOutPath and StandardErrorPath keys. Something like:

  <key>StandardOutPath</key>
  <string>/tmp/lockscreenbattery.out</string>
  <key>StandardErrorPath</key>
  <string>/tmp/lockscreenbattery.err</string>

... then examine the results to see what's happening as the job runs. (Note: since this is a launch daemon, not an agent, you could probably send the output&errors to /var/log/ instead of /tmp/. Launch agents wouldn't have permission to write there.)

1
  • Also, to have it run every minute you need this: <key>ThrottleInterval</key> <integer>60</integer> Commented Feb 17, 2023 at 16:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .