0Pricing
Linux Command Line & Bash Scripting Mastery · Aula

Arquivos temporários seguros e diretórios de bloqueio

Use mktemp e flock para criar recursos temporários sem condições de corrida e impedir execuções simultâneas de scripts.

Arquivos temporários seguros e diretórios de bloqueio é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

Por que arquivos temporários são um risco de segurança

Os scripts Bash frequentemente precisam de armazenamento temporário — resultados intermediários, marcadores de bloqueio e áreas de preparação. Mas criar arquivos temporários de forma descuidada abre vulnerabilidades sérias.

  • Condições de corrida: outro processo pode prever seu nome de arquivo e criar o arquivo primeiro, redirecionando suas gravações.
  • Ataques por links simbólicos: um invasor cria um link simbólico no caminho esperado, apontando para um arquivo sensível como /etc/passwd.
  • Arquivos deixados para trás: se um script falhar, os arquivos temporários se acumulam e podem expor dados sensíveis.

As duas ferramentas principais que eliminam esses problemas são mktemp e flock. Nesta lição, você aprenderá a usar ambas com segurança e de forma defensiva.

Criando arquivos temporários seguros com mktemp

mktemp cria um arquivo temporário com um nome aleatório e imprevisível e retorna seu caminho. Ele cria o arquivo atomicamente, portanto nenhum outro processo pode obter o nome primeiro.

  • Sintaxe: mktemp [TEMPLATE] — o modelo deve terminar com pelo menos três caracteres X.
  • Cada X é substituído por um caractere aleatório, produzindo um nome único como /tmp/script.aB3kQz.
  • O arquivo é criado automaticamente com as permissões 0600 (legível somente pelo proprietário).

Sempre capture imediatamente o caminho retornado em uma variável para que você possa referenciá-lo e removê-lo posteriormente.

#!/usr/bin/env bash
set -euo pipefail

# Create a secure temp file
TMPFILE=$(mktemp /tmp/myapp.XXXXXX)
echo "Temp file created at: $TMPFILE"

# Write data to it
echo "some intermediate result" > "$TMPFILE"

# Read it back
cat "$TMPFILE"

# Clean up
rm -f "$TMPFILE"

Sempre faça a limpeza com uma armadilha

Se o script for encerrado inesperadamente — devido a um erro, a um sinal ou ao acionamento de set -e —, os arquivos temporários permanecerão no sistema, a menos que você registre um manipulador de limpeza.

O comando integrado trap executa um comando quando o shell recebe um sinal ou é encerrado. O padrão consagrado para a limpeza de arquivos temporários é:

  • Registre a armadilha imediatamente depois de criar o arquivo temporário.
  • Registre a armadilha em EXIT para que a limpeza seja executada tanto no encerramento normal quanto no anormal.
  • Registre também as armadilhas INT e TERM se o script for demorado ou interativo.

Isso garante que não haja arquivos órfãos, mesmo que o script seja encerrado durante a execução.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/report.XXXXXX)

# Register cleanup before doing any real work
cleanup() {
    rm -f "$TMPFILE"
    echo "Cleaned up $TMPFILE" >&2
}
trap cleanup EXIT

# Do work — even if this fails, cleanup() will run
echo "Processing..." > "$TMPFILE"
grep "result" "$TMPFILE" || true

echo "Done. File will be removed on exit."

Criando diretórios temporários com mktemp -d

Às vezes, é necessário ter um diretório inteiro para preparar vários arquivos — por exemplo, ao criar um arquivo compactado ou extrair um tarball antes do processamento. Use mktemp -d para criar um diretório temporário seguro.

  • O diretório é criado com as permissões 0700 (acesso somente do proprietário).
  • Faça a limpeza com rm -rf no seu trap — tenha cuidado para remover somente a variável, nunca um caminho fixo.
  • Use aspas duplas e verifique se a variável não está vazia antes de chamar rm -rf, como uma verificação de segurança adicional.
#!/usr/bin/env bash
set -euo pipefail

TMPDIR=$(mktemp -d /tmp/extract.XXXXXX)

cleanup() {
    # Guard: only rm if variable is set and non-empty
    [[ -n "${TMPDIR:-}" ]] && rm -rf "$TMPDIR"
}
trap cleanup EXIT

echo "Working in $TMPDIR"

# Simulate staging files
echo "file one" > "$TMPDIR/part1.txt"
echo "file two" > "$TMPDIR/part2.txt"

ls "$TMPDIR"
echo "All done."

O problema das execuções simultâneas de scripts

Tarefas do Cron, temporizadores do systemd e scripts acionados manualmente podem iniciar facilmente várias instâncias do mesmo script ao mesmo tempo. Isso causa:

  • Processamento duplicado: Os mesmos registros do banco de dados ou arquivos são processados duas vezes.
  • Saída corrompida: Duas instâncias escrevem simultaneamente no mesmo arquivo de saída.
  • Deadlocks ou estado parcial: Ambas as instâncias modificam recursos compartilhados em uma ordem intercalada e imprevisível.

A solução tradicional era gravar um arquivo PID e verificá-lo na inicialização — mas essa abordagem apresenta uma janela de condição de corrida entre a verificação e a gravação. A solução moderna correta é flock, que usa o mecanismo de bloqueio consultivo do kernel para garantir um bloqueio sem condições de corrida.

Bloqueio com flock: o padrão de uma linha

flock adquire um bloqueio consultivo em um descritor de arquivo antes de executar um comando. O uso mais simples envolve todo o seu script a partir da linha de comando:

flock -n /var/lock/myscript.lock bash myscript.sh

  • -n (não bloqueante): encerra imediatamente com o status 1 se o bloqueio já estiver mantido, em vez de aguardar.
  • Sem -n, flock bloqueia até que o bloqueio fique disponível — útil para enfileiramento.
  • O próprio arquivo de bloqueio é apenas um marcador; seu conteúdo não importa. É seguro mantê-lo entre as execuções.
  • Quando o processo que mantém o bloqueio é encerrado, o kernel o libera automaticamente — não é necessária nenhuma limpeza manual.
#!/usr/bin/env bash
# launcher.sh — prevents concurrent runs of worker.sh
set -euo pipefail

LOCKFILE="/tmp/myworker.lock"

if ! flock -n "$LOCKFILE" bash -c 'echo "Running worker..."; sleep 2; echo "Done."'; then
    echo "Another instance is already running. Exiting." >&2
    exit 1
fi

flock dentro de um script usando um descritor de arquivo

Para fazer o bloqueio dentro de um script, em vez de envolvê-lo externamente, use exec para abrir um descritor de arquivo e, em seguida, chame flock nesse descritor. Esse é o padrão idiomático usado em scripts de produção.

  • exec 200>"$LOCKFILE" abre o arquivo no descritor 200 para gravação (criando-o se necessário).
  • flock -n 200 tenta bloquear o descritor 200 sem bloquear.
  • Como o bloqueio está vinculado ao descritor de arquivo (não ao nome do arquivo), ele é liberado automaticamente quando o processo do shell é encerrado.
  • Os números de descritor de 200 a 299 são usados convencionalmente para evitar conflitos com stdin/stdout/stderr.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/myjob.lock"

# Open lock file on FD 200
exec 200>"$LOCKFILE"

# Attempt non-blocking lock
if ! flock -n 200; then
    echo "ERROR: Another instance of this script is running." >&2
    exit 1
fi

echo "Lock acquired. Starting work..."
sleep 1
echo "Work complete. Lock will be released on exit."

Combinando mktemp e flock em um único script

Scripts defensivos reais precisam dos dois recursos: um bloqueio para impedir execuções simultâneas e arquivos temporários seguros para dados intermediários. Veja o padrão completo que combina as duas técnicas:

  • Adquira primeiro o bloqueio — antes de criar qualquer arquivo temporário — para que apenas uma instância execute qualquer trabalho.
  • Crie os recursos temporários depois que o bloqueio for confirmado.
  • Registre o trap imediatamente após criar os recursos temporários, para que a limpeza seja garantida independentemente de como o script seja encerrado.
  • O arquivo de bloqueio nunca deve ficar no diretório temporário — ele precisa persistir entre as execuções para que flock possa referenciá-lo.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/report_builder.lock"
exec 200>"$LOCKFILE"

if ! flock -n 200; then
    echo "Already running — aborting." >&2
    exit 1
fi

# Now safe to create temp resources
TMPDIR=$(mktemp -d /tmp/report.XXXXXX)
TMPLOG=$(mktemp /tmp/report_log.XXXXXX)

cleanup() {
    rm -rf "${TMPDIR:-}"
    rm -f  "${TMPLOG:-}"
}
trap cleanup EXIT

echo "Building report in $TMPDIR" | tee "$TMPLOG"
echo "Step 1 complete"             >> "$TMPLOG"
cat "$TMPLOG"

Diretórios de bloqueio como mecanismo alternativo

Em sistemas nos quais flock não está disponível (alguns sistemas embarcados ou sistemas de arquivos de rede, como NFS), você pode usar diretórios de bloqueio. mkdir é atômico em sistemas POSIX: ele só é bem-sucedido se o diretório ainda não existir.

  • Crie o diretório de bloqueio com mkdir /tmp/myscript.lock.d — se outra instância já o tiver criado, mkdir falhará imediatamente.
  • Armazene metadados (como o PID) dentro do diretório para fins de diagnóstico.
  • Sempre remova o diretório em um trap para EXIT.
  • Observação: Ao contrário de flock, um bloqueio de diretório NÃO é liberado automaticamente se o processo for encerrado com -9 ou se a máquina for reiniciada — adicione uma verificação para detectar bloqueios obsoletos.
#!/usr/bin/env bash
set -euo pipefail

LOCKDIR="/tmp/myscript.lock.d"

# Atomic mkdir — fails if directory already exists
if ! mkdir "$LOCKDIR" 2>/dev/null; then
    # Check if the holding PID is still alive
    HOLDER_PID=$(cat "$LOCKDIR/pid" 2>/dev/null || echo "")
    if [[ -n "$HOLDER_PID" ]] && kill -0 "$HOLDER_PID" 2>/dev/null; then
        echo "Locked by PID $HOLDER_PID. Exiting." >&2
        exit 1
    else
        echo "Stale lock detected. Removing and continuing." >&2
        rm -rf "$LOCKDIR"
        mkdir "$LOCKDIR"
    fi
fi

echo "$$" > "$LOCKDIR/pid"
trap 'rm -rf "$LOCKDIR"' EXIT

echo "Lock acquired via directory. Running..."
sleep 1
echo "Done."

Espera com tempo limite usando flock

Às vezes, você deseja aguardar um bloqueio em vez de falhar imediatamente — mas não quer esperar para sempre. flock oferece suporte a um tempo limite com a opção -w.

  • flock -w 10 200 aguarda até 10 segundos pelo bloqueio e, em seguida, encerra com o status 1 se ele ainda estiver indisponível.
  • Isso é ideal para scripts que devem aguardar na fila atrás de um processo predecessor de curta duração, mas desistir se esse processo estiver travado.
  • Combine -w com uma mensagem de erro significativa que inclua o contexto — o caminho do arquivo de bloqueio e por quanto tempo você aguardou — para que os operadores possam diagnosticar travamentos rapidamente.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/data_sync.lock"
TIMEOUT=15

exec 200>"$LOCKFILE"

echo "Waiting up to ${TIMEOUT}s for lock on $LOCKFILE..."

if ! flock -w "$TIMEOUT" 200; then
    echo "ERROR: Could not acquire lock after ${TIMEOUT}s." \
         "Another instance may be hung." >&2
    exit 1
fi

echo "Lock acquired. Syncing data..."
sleep 1
echo "Sync complete."

Lista de verificação defensiva: recursos temporários seguros

Antes de distribuir qualquer script que use arquivos temporários ou bloqueios, percorra esta lista de verificação:

  • Use mktemp, nunca caminhos fixos — /tmp/myapp.tmp é previsível e pode ser explorado.
  • Capture o caminho imediatamente — TMPFILE=$(mktemp ...) antes de qualquer outro comando.
  • Registre trap cleanup EXIT imediatamente após a criação — não no final do script.
  • Coloque aspas duplas em todos os usos de variáveis — rm -f "$TMPFILE", nunca rm -f $TMPFILE.
  • Prefira flock a arquivos PID — gerenciado pelo kernel e liberado automaticamente em caso de falha.
  • Use -n não bloqueante por padrão — bloqueios silenciosos que aguardam ocultam problemas de desempenho.
  • Coloque o arquivo de bloqueio fora do diretório temporário — para que ele sobreviva ao trap de limpeza.
  • Teste o comportamento da limpeza — execute o script e aplique kill -9 durante a execução; verifique se não restam arquivos (em scripts baseados em flock; bloqueios de diretório exigem cuidado adicional).

Verificação de conhecimento: comportamento das opções de flock

Uma tarefa do Cron é executada a cada minuto e processa um arquivo compartilhado. Você deseja que qualquer nova invocação se encerre imediatamente com um erro se uma execução anterior ainda estiver ativa, sem aguardar. Qual invocação de flock implementa isso corretamente?

Recapitulação: arquivos temporários seguros e diretórios de bloqueio

Nesta lição, você aprendeu as duas ferramentas essenciais para o gerenciamento defensivo de recursos no Bash:

  • mktemp cria arquivos temporários (0600) e diretórios (0700) com permissões seguras e nomes imprevisíveis, eliminando condições de corrida e ataques por links simbólicos que afetam caminhos fixos.
  • trap cleanup EXIT garante a remoção de arquivos temporários em qualquer encerramento — normal, causado por erro ou causado por sinal — quando registrado imediatamente após a criação.
  • flock fornece bloqueio consultivo imposto pelo kernel: use -n para falhar rapidamente em caso de contenção, -w N para aguardar com um tempo limite e o padrão exec 200>file para bloqueio dentro do script, que o kernel libera automaticamente quando o processo é encerrado.
  • Diretórios de bloqueio (mkdir) oferecem uma alternativa portátil para ambientes nos quais flock não está disponível, mas exigem detecção explícita de bloqueios obsoletos.
  • Mantenha sempre o arquivo de bloqueio fora do diretório temporário e coloque aspas duplas em todas as variáveis usadas na limpeza.

A combinação de mktemp + flock + trap produz scripts seguros contra invocações simultâneas, falhas imprevisíveis e manipulação mal-intencionada do sistema de arquivos.

Perguntas Frequentes

A aula “Arquivos temporários seguros e diretórios de bloqueio” é grátis?

Sim — o texto completo de “Arquivos temporários seguros e diretórios de bloqueio” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que vou aprender em “Arquivos temporários seguros e diretórios de bloqueio”?

Use mktemp e flock para criar recursos temporários sem condições de corrida e impedir execuções simultâneas de scripts. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?

Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Arquivos temporários seguros e diretórios de bloqueio”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?

Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Modo estrito com set -euo pipefail
  2. Manipuladores trap para limpeza e sinais
  3. Arquivos temporários seguros e diretórios de bloqueio
  4. Scripts idempotentes e lógica de novas tentativas com espera progressiva
← Voltar para Linux Command Line & Bash Scripting Mastery