Salta al contenuto principale

at: eseguire un comando una volta sola, all'ora giusta

Inviato da tuxsa il

Devi riavviare il server, ma non adesso: stanotte alle quattro, quando i visitatori sono pochi. Oppure vuoi togliere tra un'ora la pagina di manutenzione, o fare una copia di sicurezza prima di andare a dormire. crontab (vedi l'articolo relativo) è fatto per le cose che si ripetono, at per quelle che accadono una volta sola.

Cos'è

at ("alle", come in "alle 4") è un piccolo programma di pianificazione. Funziona insieme a un servizio, atd, che resta in attesa in sottofondo e al momento giusto esegue i comandi che gli hai affidato. Sulle installazioni minime di Debian e Ubuntu non è presente: si aggiunge con sudo apt install at (vedi l'articolo su apt).

Cosa fa

Accetta un orario e un elenco di comandi, li mette in una coda e li esegue quando arriva il momento, una volta, poi dimentica il lavoro. Ricorda anche l'ambiente in cui l'hai programmato (cartella corrente, variabili) e permette di vedere, annullare o riprogrammare quello che hai in attesa.

Come si usa

$ at [opzioni] orario

Gli esempi usano il server web01 degli articoli precedenti. Ho installato at 3.2.5 in un sandbox e ne ho provato i formati d'orario, la coda, -f, atrm e l'esecuzione dei lavori; le date negli esempi sono illustrative, e i nomi dei giorni sono in inglese perché at li scrive così.

Esempio 1: il comando di base

$ at 03:00 tomorrow
warning: commands will be executed using /bin/sh
at> /home/enzo/bin/backup.sh > /home/enzo/backup.log 2>&1
at> <EOT>
job 7 at Wed Nov  4 03:00:00 2026
$ echo "/home/enzo/bin/backup.sh > /home/enzo/backup.log 2>&1" | at 03:00 tomorrow
job 7 at Wed Nov  4 03:00:00 2026

Dopo l'orario, at mostra un invito (at>) in cui scrivere i comandi, uno per riga; si termina con Ctrl+d, che compare come <EOT>. Alla fine risponde con il numero del lavoro (job 7) e con l'ora esatta in cui verrà eseguito. Il secondo modo è equivalente ma più comodo negli script: i comandi arrivano da echo attraverso una pipe (vedi l'articolo su echo e tee). L'avviso sulla /bin/sh è normale: i comandi vengono eseguiti con la shell semplice e non con bash.

Esempio 2: come scrivere l'orario

$ echo "comando" | at 14:30
$ echo "comando" | at 2:30pm
$ echo "comando" | at noon
$ echo "comando" | at midnight
$ echo "comando" | at teatime
$ echo "comando" | at now + 2 hours
$ echo "comando" | at now + 90 minutes
$ echo "comando" | at 08:00 tomorrow
$ echo "comando" | at 4pm + 3 days
$ echo "comando" | at 10:00 Mon
$ echo "comando" | at 10:00 next month
$ echo "comando" | at 10:00 Nov 20
$ echo "comando" | at 10:00 10.11.2026
$ echo "comando" | at 09:00 2026-11-10
$ at -t 202612010830

at capisce un linguaggio molto libero, in inglese. Per l'ora: 14:30 o 2:30pm, e parole come noon (mezzogiorno), midnight (mezzanotte), teatime (le 16:00!) e now (adesso). Gli intervalli si scrivono con un +: now + 2 hours, + 90 minutes, + 3 days, + 1 week (le unità sono minutes, hours, days, weeks, months, years). Per la data: tomorrow, un giorno della settimana (Mon), un mese e un giorno (Nov 20), oppure 10.11.2026 (giorno, mese, anno) o 2026-11-10 (anno, mese, giorno). Con -t si scrive l'orario nel formato compatto AAAAMMGGhhmm. Se l'ora indicata è già passata oggi, il lavoro slitta a domani: alle 7:29, at 07:00 dà il giorno dopo.

Esempio 3: vedere, controllare e annullare

$ atq
7       Wed Nov  4 03:00:00 2026 a enzo
9       Thu Dec 31 17:30:00 2026 a enzo
$ at -l
$ at -c 7
#!/bin/sh
# atrun uid=1000 gid=1000
# mail enzo 0
umask 22
HOME=/home/enzo; export HOME
...
cd /home/enzo || {
         echo 'Execution directory inaccessible' >&2
         exit 1
}
/home/enzo/bin/backup.sh > /home/enzo/backup.log 2>&1
$ atrm 9
$ atq | wc -l
1

atq (at queue), o at -l (list), elenca i lavori in attesa: numero, ora di esecuzione, la coda (una lettera, a per i lavori normali) e l'utente. Un utente normale vede solo i propri; root vede tutto. Con at -c N (cat) si legge che cosa verrà eseguito: at ha ricopiato tutto l'ambiente (variabili d'ambiente, umask: vedi l'articolo su export), la cartella in cui eri (cd ...) e, in fondo, i tuoi comandi. Qui ho ridotto le righe delle variabili con i puntini. Per annullare un lavoro, atrm N (at remove, o at -d N): ne puoi indicare più di uno.

Esempio 4: da un file, o con più righe

$ at -f /home/enzo/bin/backup.sh 03:00 tomorrow
warning: commands will be executed using /bin/sh
job 8 at Wed Nov  4 03:00:00 2026
$ at now + 2 minutes <<'FINE'
cd /var/www
tar czf /mnt/dati/www.tgz .
echo "backup finito $(date +%T)" >> /home/enzo/backup.log
FINE
job 9 at Tue Nov  3 07:32:00 2026

Con -f file (file) i comandi vengono letti da un file: di solito uno script già pronto. Con un blocco di testo (here document: il pezzo tra <<'FINE' e la riga FINE) si scrivono più righe senza aprire l'invito interattivo: ideale negli script. Gli apici attorno a FINE fanno sì che $(date +%T) venga calcolato al momento dell'esecuzione, e non subito. Ho provato entrambe le forme: i comandi sono stati eseguiti all'ora prevista.

Esempio 5: dove va l'uscita

$ echo "/home/enzo/bin/backup.sh" | at 03:00
$ echo "/home/enzo/bin/backup.sh > /home/enzo/backup.log 2>&1" | at 03:00
$ echo "/home/enzo/bin/backup.sh" | at -m 03:00
$ echo "/home/enzo/bin/backup.sh" | at -M 03:00

Un lavoro di at non ha uno schermo: ciò che il comando scrive viene inviato per posta all'utente (la posta locale del sistema, se esiste). Se la macchina non ha un servizio di posta, l'uscita va perduta: l'ho verificato, e persino un errore del comando sparisce senza lasciare traccia. Per questo la regola pratica è la seconda riga: reindirizza sempre l'uscita e gli errori in un file (> file 2>&1) e poi leggilo. Con -m (mail) si riceve un messaggio anche quando non c'è alcuna uscita; con -M non ne arriva mai.

Esempio 6: una rete di sicurezza per i cambiamenti rischiosi

$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
$ echo "cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config; systemctl reload ssh" \
    | sudo at now + 10 minutes
job 12 at Tue Nov  3 07:49:00 2026
$ sudo nano /etc/ssh/sshd_config
$ sudo systemctl reload ssh
(si prova ad aprire un secondo collegamento: se funziona...)
$ sudo atrm 12

Un uso da amministratori prudenti. Prima di cambiare qualcosa che potrebbe tagliarti fuori dal server (la configurazione di ssh, il firewall, la rete: vedi gli articoli su ssh e ip), si programma il ripristino della configurazione precedente tra dieci minuti. Se la modifica funziona, si annulla il lavoro con atrm; se ti sei chiuso fuori, dopo dieci minuti il server si rimette a posto da solo. Il lavoro è creato con sudo at, quindi gira come root. Il collegamento aperto prima della modifica non cade, ma lo scopri solo provando uno nuovo.

Esempio 7: lavori che non gravano sul sistema, con batch

$ echo "/home/enzo/bin/rielabora-immagini.sh" | batch
warning: commands will be executed using /bin/sh
job 15 at Tue Nov  3 07:29:00 2026
$ atq
15      Tue Nov  3 07:29:00 2026 = enzo
$ echo "comando" | at -q b 03:00

Il comando batch mette il lavoro in coda e lo avvia non a un'ora precisa, ma quando il sistema è abbastanza libero (di solito, con un carico medio sotto 1,5: vedi l'articolo su uptime). È pensato per lavori pesanti e non urgenti. Nell'elenco, il segno = al posto della lettera della coda indica un lavoro in esecuzione. Le code sono indicate da una lettera (da a a z), scelta con -q: batch usa di norma la b, e le lettere più avanti nell'alfabeto hanno una priorità più bassa.

Esempio 8: uso negli script

#!/bin/bash
# Pianifica un riavvio per le 04:00 e dice come annullarlo
JOB=$(echo "systemctl reboot" | at 04:00 tomorrow 2>&1 | awk '/^job/ {print $2}')

if [ -z "$JOB" ]; then
    echo "Pianificazione fallita (atd è attivo?)" >&2
    exit 1
fi

echo "Riavvio programmato (lavoro $JOB). Per annullare: sudo atrm $JOB"

Lo script programma un riavvio e legge il numero del lavoro dalla risposta di at (con awk: vedi l'articolo relativo), così può dire come annullarlo. Va eseguito con sudo o come root. Esiste anche un modo diretto, sudo shutdown -r 04:00, che si annulla con sudo shutdown -c; at è più generale perché può eseguire qualunque comando.

Opzioni utili

  • at orario: programma un lavoro (comandi da tastiera, da pipe o da un blocco di testo).
  • -f file: legge i comandi da un file; -t AAAAMMGGhhmm: orario in formato compatto.
  • -m: manda sempre un messaggio al termine; -M: non manda mai niente.
  • -q lettera: sceglie la coda (a-z); batch: esegue quando il carico è basso.
  • atq o at -l: elenca i lavori; at -c N: mostra cosa verrà eseguito; atrm N o at -d N: annulla.
  • /etc/at.allow, /etc/at.deny: elenchi degli utenti ammessi o esclusi.
  • crontab, shutdown -r ORA, systemd-run --on-active=: alternative per i lavori ripetuti, per il riavvio, per l'avvio dopo un'attesa.

Attenzione a

  • Il servizio atd deve essere in funzione: senza di esso il lavoro viene accettato ma non parte mai. Se vedi Can't open /run/atd.pid to signal atd. No atd running?, controlla con systemctl status atd (vedi l'articolo su systemctl) e avvialo con sudo systemctl enable --now atd.
  • L'uscita va nei file, non nel nulla: senza un servizio di posta locale, l'uscita e gli errori dei comandi spariscono. Reindirizza sempre (esempio 5), e dopo il primo lavoro controlla che il file ci sia.
  • Si usa sh, non bash: le caratteristiche tipiche di bash (come [[ ... ]] o gli array) possono dare errore. Per uno script scritto per bash, usa at -f script.sh con la prima riga #!/bin/bash, oppure chiama bash script.sh.
  • La data americana è in agguato: at 10:00 11/10/2026 significa 10 novembre (mese/giorno/anno, come negli Stati Uniti), non 11 ottobre. Con i punti, 10.11.2026, si legge giorno, mese, anno. Meglio ancora, scrivere 2026-11-10, che non dà ambiguità, oppure controllare subito l'ora esatta nella risposta di at.
  • "yesterday" non esiste, e le ore sono 24: at risponde Garbled time a formati che non capisce e Problem in hours specification a un'ora impossibile (25:00). Dopo ogni at, leggi la riga job N at ...: è la conferma di cosa ha capito.
  • La precisione è al minuto: va bene per i compiti normali, non per i lavori che richiedono il secondo esatto.
  • Non è pensato per i lavori critici: se la macchina è spenta o atd si ferma, non c'è garanzia che il lavoro parta. Per ciò che deve avvenire sempre usa crontab o un servizio di systemd; controlla con atq che il lavoro sia davvero in coda.
  • Il lavoro gira con i tuoi privilegi, e senza di te: se il comando ha bisogno di sudo con la password non può funzionare; per i comandi da amministratore, programma il lavoro con sudo at (esempio 6). Ricorda anche che non ha un terminale: i programmi interattivi non vanno bene.
  • Fuso orario e ora legale: l'orario è quello locale del server (controllalo con date: vedi l'articolo relativo). Attorno al cambio di ora, e con i server in un altro fuso, verifica la data scritta da at.
  • Chi può usarlo: se esiste /etc/at.allow, solo gli utenti elencati possono usare at; altrimenti vale /etc/at.deny (di default, contiene gli utenti di sistema come backup e bin); root può sempre. Il comando at dà un errore di permesso a chi non è ammesso.
  • Anche un lavoro può essere dimenticato: controlla ogni tanto con atq (come tmux ls e jobs) e annulla ciò che non serve.

Riepilogo

ComandoCosa fa
at 03:00 tomorrowProgramma comandi (scritti dopo l'invito, fine con Ctrl+d)
echo "cmd" | at now + 2 hoursProgramma un comando senza invito interattivo
at -f script.sh 03:00Programma i comandi di un file
at -m 03:00Avvisa per posta alla fine, anche senza uscita
atq / at -lElenca i lavori in attesa
at -c NMostra cosa verrà eseguito (ambiente e comandi)
atrm NAnnulla il lavoro N
batchEsegue quando il carico del sistema è basso
sudo systemctl enable --now atdAvvia il servizio che esegue i lavori
sudo shutdown -r 04:00Riavvio programmato (si annulla con shutdown -c)