Creare servizio launchd macOS per attività periodiche
macOS usa launchd per avviare applicazioni, script e processi in modo automatico, anche a intervalli regolari. Per creare servizio launchd macOS basta preparare un file di configurazione .plist, salvarlo nella cartella corretta e caricarlo con launchctl. Un LaunchAgent viene eseguito nella sessione dell’utente, mentre un LaunchDaemon opera a livello di sistema. La configurazione può avviare uno script all’accesso, ogni certo numero di secondi oppure in giorni e orari stabiliti. Il metodo non richiede applicazioni aggiuntive e funziona con gli strumenti integrati in macOS.
LaunchAgent o LaunchDaemon: quale servizio usare
La scelta principale riguarda il contesto di esecuzione. Un LaunchAgent appartiene a un utente specifico e può interagire con la sua sessione grafica; un LaunchDaemon viene invece caricato dal sistema e non dispone normalmente dell’ambiente grafico dell’utente.
Per un’attività personale, come una copia periodica, la pulizia di una cartella o l’esecuzione di uno script nella propria home, LaunchAgent è generalmente la scelta più semplice. Il relativo file .plist va salvato in:
~/Library/LaunchAgents/
Un servizio di sistema usa invece:
/Library/LaunchDaemons/
I file presenti in /Library/LaunchDaemons/ richiedono normalmente privilegi amministrativi, devono appartenere a root e non dovrebbero essere usati per attività che necessitano della sessione grafica. Esiste anche /System/Library/LaunchAgents/ e /System/Library/LaunchDaemons/, ma queste directory sono gestite da macOS e non devono essere modificate.
Un file plist deve avere un identificatore stabile e un nome coerente, per esempio com.esempio.backup-periodico.plist. Il campo Label deve corrispondere all’identificatore del servizio, perché viene usato da launchctl per controllarlo.
Come creare uno script periodico per macOS
L’esempio seguente crea uno script che registra data e ora in un file di log nella cartella dell’utente. Il percorso /Users/NOME_UTENTE/Library/Logs va sostituito con il nome breve dell’account macOS.
Passo 1: preparare lo script
Creare la cartella per lo script e aprire il file con un editor da Terminale:
mkdir -p "$HOME/bin" "$HOME/Library/Logs" nano "$HOME/bin/attivita-periodica.sh"
Inserire questo contenuto:
#!/bin/zsh LOG="$HOME/Library/Logs/attivita-periodica.log" printf '%sn' "Esecuzione: $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG"
Salvare il file e renderlo eseguibile:
chmod +x "$HOME/bin/attivita-periodica.sh"
Il percorso dello script deve essere assoluto nella configurazione launchd. Non è consigliabile affidarsi a variabili come $PATH, perché l’ambiente disponibile a launchd può essere più limitato rispetto a quello di una shell interattiva.
Passo 2: creare il file plist
Aprire il file nella directory degli agenti personali:
nano "$HOME/Library/LaunchAgents/com.esempio.attivita-periodica.plist"
Inserire una configurazione basata sull’intervallo:
<?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.esempio.attivita-periodica</string> <key>ProgramArguments</key> <array> <string>/bin/zsh</string> <string>/Users/NOME_UTENTE/bin/attivita-periodica.sh</string> </array> <key>StartInterval</key> <integer>3600</integer> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>/tmp/attivita-periodica.out</string> <key>StandardErrorPath</key> <string>/tmp/attivita-periodica.err</string> </dict> </plist>
StartInterval indica un intervallo in secondi: il valore 3600 richiede l’avvio periodico a distanza di circa un’ora. RunAtLoad avvia lo script anche quando il servizio viene caricato, mentre ProgramArguments contiene il programma da eseguire e i suoi argomenti separati in elementi distinti.
Il file deve usare il percorso reale dell’utente. Per conoscere il nome breve dell’account si può eseguire:
whoami
Il timer di launchd non è pensato per garantire un’esecuzione al secondo: macOS può posticipare un’attività per ottimizzare consumi e risorse. Per un orario preciso del giorno è preferibile StartCalendarInterval.
Come caricare e controllare il servizio con launchctl
Prima di caricare il file, verificare che la sintassi XML sia valida:
plutil -lint "$HOME/Library/LaunchAgents/com.esempio.attivita-periodica.plist"
Se il comando restituisce OK, caricare il servizio nel dominio grafico dell’utente corrente:
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.esempio.attivita-periodica.plist"
Il comando bootstrap registra l’agent nel dominio dell’utente. Per avviarlo immediatamente senza attendere l’intervallo, usare il valore Label definito nel file:
launchctl kickstart -k "gui/$(id -u)/com.esempio.attivita-periodica"
Lo stato del servizio può essere controllato con:
launchctl print "gui/$(id -u)/com.esempio.attivita-periodica"
Il file /tmp/attivita-periodica.out contiene l’output standard del processo, mentre /tmp/attivita-periodica.err raccoglie gli errori. Nel caso dell’esempio, l’attività scrive inoltre direttamente nel file ~/Library/Logs/attivita-periodica.log.
Per rimuovere il servizio dal dominio dell’utente senza cancellare il file .plist, eseguire:
launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.esempio.attivita-periodica.plist"
Dopo aver modificato il file di configurazione, è consigliabile eseguire prima bootout e poi nuovamente bootstrap, perché la modifica del file non aggiorna sempre automaticamente il servizio già caricato.
Come eseguire un’attività in giorni e orari specifici
StartCalendarInterval permette di associare l’esecuzione a uno o più campi temporali. Per esempio, questa configurazione avvia lo script ogni giorno alle 23:30:
<key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>23</integer> <key>Minute</key> <integer>30</integer> </dict>
Al posto di StartInterval va usato un solo criterio temporale, salvo esigenze specifiche. È possibile indicare anche Weekday, con valori numerici definiti dalla documentazione Apple, ma per evitare errori è preferibile verificare il comportamento sulla versione di macOS in uso.
I parametri più utili per attività periodiche sono:
ProgramArguments, per indicare eseguibile e argomenti.StartInterval, per un intervallo espresso in secondi.StartCalendarInterval, per un giorno o un orario del calendario.RunAtLoad, per eseguire il processo appena il servizio viene caricato.StandardOutPatheStandardErrorPath, per salvare output ed errori.WorkingDirectory, per impostare la directory di lavoro del processo.EnvironmentVariables, per definire variabili d’ambiente esplicite.
Uno script che richiede accesso a cartelle protette, unità di rete o dati personali può essere limitato dalle autorizzazioni di privacy di macOS. Inoltre, un LaunchAgent viene eseguito nella sessione dell’utente, mentre un LaunchDaemon non dovrebbe essere progettato assumendo la presenza di Finder, Dock o altre applicazioni grafiche.
Per creare servizio launchd macOS in modo affidabile, usare percorsi assoluti, registrare gli errori e verificare sempre il servizio con launchctl print.
FAQ
Un LaunchAgent personale va salvato in ~/Library/LaunchAgents/. I servizi di sistema usano invece /Library/LaunchDaemons/ e richiedono configurazioni e permessi più restrittivi.
launchd non interpreta automaticamente una riga come farebbe una shell. Per usare comandi shell, indica /bin/zsh o /bin/bash come primo elemento e il percorso assoluto dello script come secondo elemento.
Inserisci <key>StartInterval</key> con <integer>3600</integer> nel file .plist, poi carica il servizio con launchctl bootstrap.
Controlla la sintassi con plutil -lint, verifica i percorsi assoluti e consulta StandardErrorPath. Anche permessi errati, identificatori incoerenti o restrizioni di privacy possono impedire l’esecuzione.
Esegui launchctl bootout per rimuoverlo dal dominio caricato e cancella il relativo file .plist dalla directory LaunchAgents o LaunchDaemons.
Altri articoli di questa serie:
- Mostrare file nascosti macOS Terminale: comando rapido
- Disattivare riapertura finestre macOS: metodo rapido
- Personalizzare anteprime icone Finder con defaults
- Percorso completo Finder macOS nella barra del titolo
- Disattivare DS_Store unità di rete Mac: metodo rapido
- Ricerca metadati Spotlight Terminale con mdls e mdfind
- Ricostruire indice Spotlight macOS Terminale
- Controllare consumo energetico Mac Terminale con powermetrics
- Trovare i processi che rallentano il Mac da Terminale
- Controllare la pressione memoria macOS Terminale
- Come misurare l’avvio lento delle app su Mac
- Leggere log macOS da Terminale: comandi utili
- Rapporto processi bloccati macOS spindump: come crearlo
- Verificare firma applicazioni macOS Terminale
- Permessi privacy delle app Mac: come controllarli
- Gestire programmi avvio automatico macOS con launchctl
- Confrontare cartelle macOS Terminale con diff
- Rinominare file in massa su macOS dal Terminale
- Proteggere file sensibili su macOS dal Terminale
