IFCE Horizonte · Portal
ADS23 · Sistemas Operacionais

Mão na massa · ~49 min

Construindo um script de monitoramento, peça por peça

Hoje você não escreve vários scripts soltos — escreve um só, que cresce a cada passo. No fim, ele verifica o disco, decide se há problema, registra em log e avisa. É o mesmo tipo de ferramenta que roda de madrugada em servidores reais.

Passos 1–6 · Do primeiro script ao monitor completoPasso 7 · Reforço Docker: script que controla container

📖 Este roteiro é a leitura obrigatória da semana

Nenhum dos dois livros-base da disciplina cobre shell script. Por isso, nesta semana, este documento substitui o capítulo de livro — e o quiz cobra o conteúdo dele.

Leia as explicações, não só os comandos. Os blocos "o que é" e "por que importa" são o conteúdo teórico da semana.

Passo 1 de 7

O primeiro script que roda

Um script é um arquivo de texto com comandos. Três coisas o tornam executável: o shebang, o conteúdo e a permissão.
1nano ~/monitor.sh

O que é

A primeira linha, #!/bin/bash, é o shebang: diz ao sistema qual programa deve interpretar este arquivo. Sem ela, o SO não sabe que é um script bash.

Por que importa

É o que transforma um arquivo de texto qualquer num programa executável. Nenhuma compilação é necessária — o shell já é o interpretador.

#!/bin/bash

echo "Monitor de sistema"
echo "Executado por: $USER"
O que esperar:

salve com Ctrl+O, Enter, Ctrl+X. Depois rode chmod +x ~/monitor.sh e execute com ~/monitor.sh. O $USER é uma variável que o próprio sistema já define com seu nome de usuário.

Deu "Permission denied"

Faltou o chmod +x ~/monitor.sh. Esse é o erro mais comum de quem começa: o arquivo existe e o conteúdo está certo, mas sem a permissão de execução o sistema se recusa a rodá-lo. Confira com ls -l ~/monitor.sh — devem aparecer x nas permissões.

Passo 2 de 7

Variáveis e a captura da saída de um comando

Este é o conceito mais importante do encontro: um script pode guardar o resultado de um comando numa variável e decidir o que fazer com ele.
2Acrescente ao monitor.sh

O que é

VAR="valor" atribui — sem espaços em volta do =. $(comando) executa o comando e devolve a saída dele, que pode ser guardada numa variável.

Por que importa

É o que permite o script reagir ao estado real da máquina, em vez de executar sempre a mesma coisa cegamente.

#!/bin/bash

LIMITE=80
DATA=$(date +%F)
USO=$(df / | tail -1 | awk '{print $5}' | tr -d '%')

echo "Data: $DATA"
echo "Uso do disco: ${USO}%"
echo "Limite configurado: ${LIMITE}%"
O que esperar:

o script imprime a data de hoje e o percentual real de uso do seu disco. A linha do USO é um pipeline do Encontro 6: pega a saída do df, fica com a última linha, extrai a 5ª coluna e remove o símbolo % — sobrando só o número.

Por que as chaves em ${USO}%?

As chaves delimitam onde o nome da variável termina. Sem elas, $USO% ainda funcionaria neste caso, mas $USOpercent faria o shell procurar uma variável chamada USOpercent, que não existe. Usar ${} sempre que houver texto colado é um bom hábito.

Erro: "LIMITE: command not found"

Você deixou espaço em volta do =. Em bash, LIMITE = 80 é interpretado como "execute o comando LIMITE com os argumentos = e 80". Escreva sempre LIMITE=80, sem espaço algum.

o que a construção $(...) faz, e por que ela é essencial para um script de monitoramento? Use a linha do USO como exemplo.

0 / 40 caracteres

Passo 3 de 7

Fazendo o script decidir

Com o valor capturado, o script pode comparar e agir de formas diferentes conforme o resultado.
3Acrescente a condicional

O que é

if [ condição ]; then ... else ... fi. Os espaços dentro dos colchetes são obrigatórios, e -gt significa "maior que" para números.

Por que importa

Sem condicional, um monitor não monitora — ele apenas imprime. É o if que transforma dado em decisão.

if [ "$USO" -gt "$LIMITE" ]; then
echo "ALERTA: disco em ${USO}%, acima do limite de ${LIMITE}%"
else
echo "OK: disco em ${USO}%, dentro do limite"
fi
O que esperar:

provavelmente a mensagem "OK". Para testar o outro caminho, baixe temporariamente o limite (LIMITE=10) e rode de novo — o script deve passar a alertar. Depois volte para 80.

Por que as aspas em "$USO" e "$LIMITE"?

Sem aspas, uma variável vazia desaparece da linha, e uma com espaços vira várias palavras. O caso mais traiçoeiro é o teste de texto: com NOME vazio, [ -n $NOME ] vira [ -n ], que dá verdadeiro — o script conclui que há um nome quando não há. Com aspas, [ -n "$NOME" ] vira [ -n "" ], que dá falso, como deveria. Sempre use aspas em volta de variáveis — é a regra que evita mais bugs em shell script.

Atenção a um limite da regra: no teste numérico, aspas não bastam. Se USO vier vazio, tanto [ $USO -gt 80 ] quanto [ "$USO" -gt "80" ] imprimem um erro, a condição fica falsa e o script cai no else — dizendo "OK" sem ter medido nada. Por isso um monitor sério confere antes se o valor é mesmo um número (é o desafio do fim do roteiro).

Erro: "[: missing ]" ou similar

Faltou espaço dentro dos colchetes. [$USO -gt $LIMITE] está errado; o certo é [ "$USO" -gt "$LIMITE" ], com espaço depois do [ e antes do ]. O [ é, na verdade, um comando — e comandos precisam ser separados dos argumentos por espaço.

Passo 4 de 7

Repetindo para vários itens

O laço for aplica uma sequência inteira de comandos a cada item de uma lista — indo além do que o coringa do Encontro 12 permitia.
4Acrescente o laço

O que é

for VAR in lista; do ... done. A cada volta, VAR assume o valor do item seguinte da lista.

Por que importa

O coringa aplica um comando a muitos arquivos. O for aplica uma sequência de decisões a cada um — inclusive com if dentro.

echo "--- Verificando pontos de montagem ---"
for PONTO in / /home /tmp; do
if [ -d "$PONTO" ]; then
  ESPACO=$(df -h "$PONTO" | tail -1 | awk '{print $4}')
  echo "$PONTO tem $ESPACO livres"
else
  echo "$PONTO não existe nesta máquina"
fi
done
O que esperar:

uma linha por caminho. O teste -d verifica se o diretório existe antes de consultar o df — assim o script não quebra se receber um caminho que não existe nesta máquina. Esse tipo de defesa é o que diferencia script frágil de script confiável. Repare também: se /home não for uma partição separada (o caso da sua VM), o df mostra o sistema de arquivos que o contém — o mesmo de / — e os dois aparecem com o mesmo espaço livre.

Passo 5 de 7

Uma função para registrar log

Quando o mesmo trecho se repete em vários pontos, ele vira função — e passa a ter um só lugar para ser corrigido.
5Adicione a função log() no topo (logo após o shebang)

O que é

nome() { ... } define a função. Dentro dela, $1 é o primeiro argumento recebido na chamada.

Por que importa

Se amanhã o formato do log mudar, você altera um lugar só — em vez de caçar todos os echo espalhados pelo script.

#!/bin/bash

ARQUIVO_LOG=~/monitor.log

log() {
echo "[$(date +'%F %T')] $1" | tee -a "$ARQUIVO_LOG"
}

# ... resto do script ...
log "Verificação iniciada"
O que esperar:

a mensagem aparece na tela e é gravada no arquivo. O tee -a faz as duas coisas ao mesmo tempo (o -a é de "append", equivalente ao >> do Encontro 12). Confira com cat ~/monitor.log.

Por que a função precisa vir antes de ser chamada?

O bash lê o script de cima para baixo. Se você chamar log numa linha anterior à definição da função, ele ainda não sabe que ela existe e dá "command not found". Por isso funções ficam sempre no topo, logo após o shebang.

qual a vantagem de usar uma função log() em vez de repetir echo em vários pontos do script?

0 / 40 caracteres

Passo 6 de 7

O script completo

Junte tudo. Este é o resultado final — um monitor de disco funcional, com log e código de saída.
6Versão final do monitor.sh

O que é

Todas as peças anteriores integradas, mais o exit com código apropriado ao final.

Por que importa

O exit 1 sinaliza erro a quem chamou o script — é assim que uma ferramenta de agendamento ou um pipeline sabe que algo deu errado.

#!/bin/bash

ARQUIVO_LOG=~/monitor.log
LIMITE=80

log() {
echo "[$(date +'%F %T')] $1" | tee -a "$ARQUIVO_LOG"
}

log "Verificação iniciada"

USO=$(df / | tail -1 | awk '{print $5}' | tr -d '%')

if [ "$USO" -gt "$LIMITE" ]; then
log "ALERTA: disco em ${USO}%, acima do limite"
exit 1
else
log "OK: disco em ${USO}%"
exit 0
fi
O que esperar:

depois de rodar, verifique o código de saída com echo $? — deve ser 0 se estiver OK. Teste também ~/monitor.sh && echo "tudo certo": a segunda parte só executa se o script sair com 0, exatamente como o && que vocês usam desde o Encontro 5.

O que esperar:

Desafio: faça o script sair com código 2 e uma mensagem de erro se USO não for um número (dica: [[ "$USO" =~ ^[0-9]+$ ]] testa se a variável só tem dígitos).

Reforço Docker · script que controla container

Passo 7 de 7

Um script que garante o container no ar

Última peça: um script que verifica se o container está rodando e, se não estiver, o sobe. É o embrião do toolkit do projeto final.
7nano ~/garante_container.sh

O que é

docker ps -q -f name=... devolve o ID do container se ele estiver rodando, ou nada se não estiver. O teste -z verifica se a variável ficou vazia.

Por que importa

É a lógica básica de qualquer ferramenta de orquestração: verificar o estado desejado e agir só quando ele não for o real.

#!/bin/bash

NOME=meuservico
RODANDO=$(docker ps -q -f name="$NOME")

if [ -z "$RODANDO" ]; then
echo "Container $NOME não está no ar. Subindo..."
docker run -d --name "$NOME" alpine sleep 600
else
echo "Container $NOME já está rodando (ID: $RODANDO)"
fi
O que esperar:

na primeira execução, o script sobe o container. Rode uma segunda vez — agora ele deve detectar que já está no ar e não fazer nada. Essa propriedade (rodar várias vezes sem causar estrago) é justamente o que se espera de um script de automação.

Segunda execução deu erro de nome já em uso

Significa que o container existe mas está parado — o docker ps -q só lista os que estão rodando. Remova com docker rm $NOME e rode de novo. Um script de produção trataria esse caso também, verificando com docker ps -aq; fica como desafio.

O que esperar:

Limpeza: docker stop meuservico && docker rm meuservico.

o que aconteceu ao rodar o garante_container.sh duas vezes seguidas? Por que essa propriedade é desejável num script de automação?

0 / 40 caracteres

Exemplo de observação forte × fraca

Observação fraca

"O $(...) executa um comando e guarda o resultado."

Observação forte

"O $(...) executa o comando e substitui a expressão pela saída dele. Na linha USO=$(df / | tail -1 | awk '{print $5}' | tr -d '%'), todo o pipeline roda primeiro e só o número final (ex.: 36) é guardado em USO. Sem isso, o script só conseguiria imprimir a saída do df na tela; com isso, ele consegue comparar esse valor com o limite e decidir se alerta. É o que separa um script que informa de um que monitora."

Checklist final

  • Criei meu primeiro script com shebang e chmod +x
  • Usei variáveis e capturei a saída de um comando com $(...)
  • Fiz o script decidir com if e testei os dois caminhos
  • Percorri uma lista com for, com if dentro
  • Criei a função log() e confirmei a gravação no arquivo
  • Montei o script completo e verifiquei o código de saída com echo $?
  • Escrevi um script que verifica e sobe um container, e rodei duas vezes
  • Li as explicações deste roteiro por inteiro (é a leitura da semana)
  • Preenchi as 3 observações acima (vou colar no quiz semanal)
0 / 9 verificados