Domine `at` e `batch`: Agendamento de tarefas únicas no Linux

Se você busca agendar uma atividade no Linux que ocorrerá apenas uma vez, o cron pode ser considerado excessivo. A família de comandos `at` é a solução ideal! E, se a intenção é executar processos somente quando o sistema estiver com recursos ociosos, o `batch` é a ferramenta adequada.

Agendamento de Tarefas no Linux

O daemon cron gerencia uma lista de trabalhos a serem executados em horários específicos. Estes trabalhos e programas são executados em segundo plano nos momentos programados, oferecendo grande flexibilidade para agendar tarefas repetitivas. Seja uma tarefa a cada hora, em um horário específico diariamente ou uma vez por mês ou ano, o cron permite essa configuração.

Entretanto, o cron não é a melhor opção para tarefas únicas. Embora seja possível configurá-lo para tal, torna-se inconveniente lembrar de remover a entrada crontab após a execução da tarefa.

No mundo Linux, se você enfrenta um problema, é provável que outros já o tenham enfrentado também. Felizmente, devido à longa história dos sistemas operacionais Unix, é bem possível que alguém já tenha criado uma solução para seu problema.

Para o cenário descrito, a solução existe e se chama `at`.

Instalação do Comando `at`

A instalação do `at` foi necessária no Ubuntu 18.04 e no Manjaro 18.1.0, pois já estava presente no Fedora 31.

Para instalar no Ubuntu, utilize:

sudo apt-get install at

Após a instalação, inicie o daemon `at` com:

sudo systemctl enable --now atd.service

No Manjaro, instale com:

sudo pacman -Sy at

Após a instalação, inicie o daemon `at` com:

sudo systemctl enable --now atd.service

Em qualquer distribuição, use este comando para verificar se o daemon `atd` está em execução:

ps -e | grep atd

Uso Interativo do Comando `at`

Para usar o `at`, é necessário definir uma data e hora de execução. A forma de expressar essa data e hora é bastante flexível, como veremos adiante.

Mesmo no uso interativo, a data e hora devem ser fornecidas previamente. Caso contrário, o `at` responderá com “Hora distorcida”, conforme exemplificado:

at
at banana

Datas e horários podem ser explícitos ou relativos. Por exemplo, para executar um comando em um minuto, use “now” e adicione “1 minute”:

at now + 1 minute

O `at` exibe uma mensagem, um prompt e aguarda a entrada de comandos. Observe a mensagem:

Ela informa que será iniciada uma instância do shell `sh` para executar os comandos dentro dele. Seus comandos não serão executados no shell Bash, que possui um conjunto de recursos mais rico.

Se seus comandos ou scripts utilizarem funcionalidades específicas do Bash, eles podem falhar ao executar no `sh`.

Para testar se seus comandos ou scripts funcionarão em `sh`, utilize o comando:

sh

O prompt mudará para `$`, permitindo testar seus comandos. Para retornar ao shell Bash, digite:

exit

Não haverá saída padrão ou mensagens de erro dos comandos, pois o shell `sh` é executado em segundo plano, sem interface de tela.

Qualquer saída dos comandos, positiva ou negativa, será enviada por e-mail ao usuário que executou o `at`, usando o sistema de correio interno. Portanto, é necessário instalar e configurar esse sistema de e-mail.

Muitos sistemas Linux não possuem um sistema de e-mail interno, devido à pouca necessidade. Os que possuem utilizam sistemas como sendmail ou postfix. Caso seu sistema não tenha, você pode direcionar a saída para arquivos para fins de registro.

Se o comando não gerar nenhuma saída ou erro, você não receberá e-mail. Muitos comandos do Linux indicam sucesso com silêncio, portanto, em geral, você não receberá e-mail.

Para exemplificar, utilizaremos um pequeno script chamado `sweep.sh` que remove arquivos `*.bak`, `*.tmp` e `*.o`. Digite o caminho para o comando e pressione Enter:

Um novo prompt é exibido, permitindo adicionar quantos comandos desejar. Geralmente, é mais prático agrupar os comandos em um único script e chamá-lo dentro do `at`.

Use Ctrl + D para indicar o fim da inserção de comandos. O `at` exibirá ``, que significa fim de transmissão. Ele informará o número do trabalho e o horário agendado para execução:

Após a execução da tarefa, verifique seu e-mail interno com:

mail

Se não houver e-mail, considere a execução bem-sucedida. Nesse caso, verifique se os arquivos `*.bak`, `*.tmp` e `*.o` foram removidos para confirmar a execução do comando.

Para executar novamente, utilize:

at now + 1 minute

Após um minuto, verifique novamente o e-mail:

mail

Se houver e-mail, pressione `1` e Enter para lê-lo.

O e-mail do `at` informa que os comandos do script geraram erros. Neste exemplo, não havia arquivos para excluir porque o script os removeu na execução anterior.

Pressione D + Enter para excluir o e-mail e Q + Enter para sair do programa de e-mail.

Formatos de Data e Hora

O `at` oferece grande flexibilidade nos formatos de hora. Seguem alguns exemplos:

Executar às 11h:

at 11:00 AM

Amanhã às 11h:

at 11:00 AM tomorrow

Executar às 11h no mesmo dia da próxima semana:

at 11:00 AM next week

Executar nesse horário, neste dia, na próxima semana:

at next week

Executar às 11h na próxima sexta-feira:

at 11:00 AM next fri

Executar nesse horário na próxima sexta-feira:

at next fri

Executar às 11h nesta data, no próximo mês:

at 11:00 AM next month

Executar às 11h em uma data específica:

at 11:00 AM 3/15/2020

Executar em 30 minutos:

at now + 30 minutes

Executar em duas horas:

at now + 2 hours

Executar amanhã nesse horário:

at tomorrow

Executar nessa hora na quinta-feira:

at thursday

Executar à meia-noite:

at midnight

Executar ao meio-dia:

at noon

Para os britânicos, é possível agendar para a hora do chá (16h):

at teatime

Visualizando a Fila de Tarefas

O comando `atq` exibe a fila de trabalhos agendados:

Para cada comando na fila, o `atq` mostra:

ID do trabalho
Data programada
Hora programada
Fila do trabalho (ex: “a”, “b”). Tarefas agendadas com `at` vão para a fila “a”, enquanto as de `batch` vão para “b”.
Usuário que agendou o trabalho.

Uso do `at` na Linha de Comando

Além do uso interativo, o `at` pode ser usado na linha de comando, facilitando seu uso em scripts.

É possível encaminhar comandos para `at` com pipes:

echo "sh ~/sweep.sh" | at 08:45 AM

O trabalho é aceito e agendado, com número e data de execução informados.

Uso do `at` com Arquivos de Comandos

É possível armazenar uma sequência de comandos em um arquivo e passá-lo para o `at`. Não precisa ser um script executável, apenas um arquivo de texto.

Use a opção `-f` (arquivo) para passar um nome de arquivo:

at now + 5 minutes -f clean.txt

O redirecionamento de arquivo também é uma opção:

at now + 5 minutes < clean.txt

Removendo Trabalhos Agendados da Fila

Para remover um trabalho da fila, use o comando `atrm`. Primeiro, use `atq` para encontrar o número do trabalho e, em seguida, use esse número com `atrm`, conforme abaixo:

atq
atrm 11
atq

Visualizando Detalhes das Tarefas

Trabalhos agendados para o futuro podem ser esquecidos. O `atq` mostra os trabalhos na fila, mas não seu conteúdo. Use a opção `-c` (cat) para visualizar detalhes de um trabalho.

Primeiro, use `atq` para encontrar o número do trabalho:

atq

Agora, use o número do trabalho (13, neste exemplo) com a opção `-c`:

at -c 13

As informações sobre o trabalho são:

Primeira linha: Indica que os comandos serão executados no shell `sh`.
Segunda linha: Os comandos serão executados com ID de usuário e grupo 1000 (usuário que executou o comando `at`).
Terceira linha: O usuário que receberá os e-mails sobre a execução.
Quarta linha: A Máscara de usuário (umask) é 22. Define as permissões padrão para arquivos criados nessa sessão `sh`. A máscara é subtraída de 666, resultando em 644 (rw-r–r– em octal).
Restante dos dados: Variáveis de ambiente.

Resultados de um teste: Verifica se o diretório de execução pode ser acessado. Se não, gera um erro e abandona a execução.
Comandos a serem executados: Listagem dos comandos e conteúdo dos scripts programados. O script (neste exemplo) foi escrito para ser executado em Bash, mas será executado em `sh`.

O Comando `batch`

O comando `batch` funciona de forma semelhante ao `at`, mas com três diferenças:

Utiliza-se apenas interativamente.
Em vez de executar em um horário específico, ele adiciona trabalhos à fila, que são executados quando a carga média do sistema é inferior a 1.5.
Não é necessário especificar data e hora.

Para usar o `batch`, basta chamá-lo, sem parâmetros:

batch

Em seguida, adicione as tarefas como faria com o comando `at`.

Controlando o Acesso ao Comando `at`

Os arquivos `at.allow` e `at.deny` controlam quem pode usar a família de comandos `at`. Eles estão localizados em `/etc`. Por padrão, apenas o `at.deny` existe, criado na instalação do `at`.

Seu funcionamento:

`at.deny`: Lista os usuários que não podem utilizar o `at`.
`at.allow`: Lista os usuários que podem utilizar o `at`. Se este arquivo não existir, o `at` usa apenas o `at.deny`.

Por padrão, todos podem usar o `at`. Para restringir o acesso, utilize o arquivo `at.allow` para listar os permitidos. É mais fácil do que adicionar todos os que não podem usar `at` ao `at.deny`.

O arquivo `at.deny`:

sudo less /etc/at.deny

Ele lista os componentes do sistema que não podem usar `at`, muitos por motivos de segurança, que não devem ser removidos.

Para editar o `at.allow`, adicione `dave` e `mary`. Somente eles terão permissão para usar `at`:

Primeiro, use:

sudo gedit /etc/at.allow

Adicione os nomes ao editor e salve o arquivo:

Se outro usuário (ex: `eric`) tentar usar o `at`:

at

Ele terá seu acesso negado:

Mesmo que `eric` não esteja no `at.deny`, ao adicionar qualquer usuário ao `at.allow`, os demais terão permissão negada.

Ideal para Tarefas Únicas

Como visto, `at` e `batch` são ideais para tarefas únicas. Para recapitular:

Use `at` para tarefas que não fazem parte do dia a dia.
Use `batch` para tarefas que precisam ser executadas apenas quando a carga do sistema estiver baixa.