Comando mktemp: Criando Arquivos Temporários Seguros

Comando mktemp: Criando Arquivos Temporários Seguros

O Que Você Vai Aprender

  • O padrão seguro para criar arquivos e diretórios temporários com mktemp
  • Por que file.$$ e arquivos temporários com nomes fixos são perigosos
  • Como combinar mktemp com trap para que a limpeza sempre ocorra

Resumo Rápido

  • Arquivo temporário -> tmp=$(mktemp)
  • Diretório temporário -> dir=$(mktemp -d)
  • Sempre adicione trap 'rm -rf "$dir"' EXIT para limpar automaticamente

Pré-requisitos

  • GNU coreutils (verifique com mktemp --version; verificado aqui na versão 9.4)
  • Uma distribuição Linux típica (Ubuntu, família RHEL, etc.)
  • O mktemp do BSD / macOS tem um conjunto de opções diferente

O Que É o mktemp?

Conclusão: mktemp cria com segurança um arquivo ou diretório temporário com nome único e imprime seu caminho na saída padrão.

mktemp cria um arquivo temporário sem colisão de nomes e imprime seu caminho, para que seu programa nunca precise inventar nomes de arquivos por conta própria.

$ mktemp
/tmp/tmp.A1b2C3d4E5

Omita o template e ele cria tmp.XXXXXXXXXX em $TMPDIR (ou /tmp se não definido). Os caracteres X são substituídos por caracteres aleatórios.

Do man page (GNU coreutils 9.4):

Create a temporary file or directory, safely, and print its name.
Files are created u+rw, and directories u+rwx, minus umask restrictions.

As duas palavras-chave são "safely" (com segurança) e "print its name" (imprime seu nome): criação e nomeação acontecem atomicamente, e somente o dono pode ler ou escrever o resultado.

Por Que Usar o mktemp?

Conclusão: Nomes fixos e nomes baseados em $$ (PID) são previsíveis, convidando condições de corrida, sobrescrita e ataques de symlink. O mktemp previne isso por design.

Padrões perigosos a evitar

# RUIM: nome fixo
tmpfile=/tmp/myapp.tmp

# RUIM: PID e previsivel e colide em execucao concorrente
tmpfile=/tmp/myapp.$$

Os problemas:

  • Condição de corrida: executar o mesmo script concorrentemente faz os nomes colidirem e corromperem os dados uns dos outros
  • Ataque de symlink: um atacante que adivinha o nome pode colocar previamente um symlink em /tmp, fazendo seu script sobrescrever um arquivo não intencional
  • Permissões expostas: criar via touch ou > depende do umask e pode resultar em arquivo legível por todos

O que o mktemp corrige

$ tmpfile=$(mktemp)
$ stat -c '%a %n' "$tmpfile"
600 /tmp/tmp.A1b2C3d4E5

mktemp realiza criação e nomeação como um único passo indivisível e falha se o arquivo já existir. Arquivos são criados com u+rw (tipicamente 600 após umask) e diretórios com u+rwx (tipicamente 700), portanto são exclusivos do dono desde o início.

Enquanto o nome for previsível, um chmod posterior não pode fechar a janela de corrida. O que importa é que o arquivo seja seguro no momento da criação.

Como Criar Arquivos e Diretórios Temporários?

Conclusão: Use mktemp para um arquivo e mktemp -d para um diretório; capture o caminho retornado em uma variável e use essa variável dali em diante.

Arquivo temporário

$ tmpfile=$(mktemp)
$ echo "data" > "$tmpfile"
$ cat "$tmpfile"
data

Diretório temporário

$ tmpdir=$(mktemp -d)
$ echo "$tmpdir"
/tmp/tmp.Xy9Zq2Lk7P

-d (--directory) cria um diretório em vez de um arquivo. Use quando precisar de vários arquivos intermediários em um só lugar, e depois limpe com um único rm -rf "$tmpdir".

Sempre coloque a variável entre aspas duplas ("$tmpfile"). Isso continua funcionando mesmo se TMPDIR apontar para um caminho contendo espaços.

Como Controlar a Localização e o Nome?

Conclusão: Um template molda o nome, -p define o diretório base, e --suffix adiciona uma extensão. O template precisa de pelo menos três Xs consecutivos no final.

Passar um template

$ mktemp myapp.XXXXXX
myapp.k3Df9a

Os Xs são substituídos por caracteres aleatórios. O GNU requer pelo menos três Xs consecutivos no último componente.

Definir o diretório base (-p / --tmpdir)

$ mktemp -p /var/tmp myapp.XXXXXX
/var/tmp/myapp.q7Zb2K

-p DIR (--tmpdir[=DIR]) define o diretório base. Como /tmp pode ser limpo na reinicialização, escolha /var/tmp para dados temporários que devem persistir um pouco mais.

Adicionar uma extensão (--suffix)

$ mktemp --suffix=.log myapp.XXXXXX
myapp.a8Kd2p.log

Útil quando uma ferramenta detecta o formato pela extensão. SUFF não pode conter uma barra.

Template vs -p / -t (notas)
  • Com -p DIR, o template não deve ser absoluto. Ele pode conter barras, mas mktemp cria apenas o componente final.
  • -t ("tratar o template como um único componente de nome de arquivo sob $TMPDIR etc.") é uma opção mais antiga, agora descontinuada. Use -p em novos scripts.

Como Limpar de Forma Confiável em um Script?

Conclusão: Adicione trap 'rm -rf "$tmpdir"' EXIT logo após a criação, e os dados temporários serão removidos tanto em saídas normais quanto em saídas por erro.

O padrão padrão para um script que cria arquivos temporários:

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

tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

# use $tmpdir livremente aqui
curl -s https://example.com/data.json > "$tmpdir/data.json"
jq '.items' "$tmpdir/data.json"

# na saida, o trap remove $tmpdir automaticamente

Pontos-chave:

  • Defina o trap imediatamente após mktemp -d (escreva criação e limpeza juntas)
  • Capturar EXIT significa que a limpeza executa mesmo quando set -e aborta no meio
  • Um único diretório permite fazer rm -rf em tudo, independente de quantos arquivos você adicionar

Veja Tratamento de Sinais e Limpeza com trap para detalhes.

Limite o alvo do trap a $tmpdir (o caminho único que mktemp retornou). Um script que faz rm -rf em um padrão amplo como /tmp/* é um acidente esperando para acontecer.

Opções e Armadilhas que Vale Conhecer

Conclusão: -u (dry-run) apenas imprime um nome sem criar nada, quebrando a garantia de segurança. Use o mktemp simples por padrão, que cria o arquivo para você.

Opção Significado Cuidado
-d Criar um diretório, não um arquivo Limpe com rm -rf
-u Apenas imprimir um nome, não criar (dry-run) Abre a janela de corrida. Evite.
-q Suprimir diagnósticos de falha na criação Quando o script trata erros por conta própria
-p DIR Definir o diretório base Template não pode ser absoluto
--suffix=SUFF Adicionar uma extensão, etc. Barra não permitida

Observe também o valor de retorno:

# RUIM: se a criacao falhar, prosseguir pode fazer rm de uma string vazia
tmpfile=$(mktemp)

# BOM: detectar falha e parar
tmpfile=$(mktemp) || exit 1

Resumo / Próximas Leituras