Comando mktemp: Criando Arquivos Temporarios Seguros
O Que Voce Vai Aprender
- O padrao seguro para criar arquivos e diretorios temporarios com
mktemp - Por que
file.$$e arquivos temporarios com nomes fixos sao perigosos - Como combinar
mktempcomtrappara que a limpeza sempre ocorra
Resumo Rapido
- Arquivo temporario ->
tmp=$(mktemp) - Diretorio temporario ->
dir=$(mktemp -d) - Sempre adicione
trap 'rm -rf "$dir"' EXITpara limpar automaticamente
Pre-requisitos
- GNU coreutils (verifique com
mktemp --version; verificado aqui na versao 9.4) - Uma distribuicao Linux tipica (Ubuntu, familia RHEL, etc.)
- O
mktempdo BSD / macOS tem um conjunto de opcoes diferente
O Que E o mktemp?
Conclusao: mktemp cria com seguranca um arquivo ou diretorio temporario com nome unico e imprime seu caminho na saida padrao.
mktemp cria um arquivo temporario sem colisao de nomes e imprime seu caminho, para que seu programa nunca precise inventar nomes de arquivos por conta propria.
$ mktemp /tmp/tmp.A1b2C3d4E5
Omita o template e ele cria tmp.XXXXXXXXXX em $TMPDIR (ou /tmp se nao definido). Os caracteres X sao substituidos por caracteres aleatorios.
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 sao "safely" (com seguranca) e "print its name" (imprime seu nome): criacao e nomeacao acontecem atomicamente, e somente o dono pode ler ou escrever o resultado.
Por Que Usar o mktemp?
Conclusao: Nomes fixos e nomes baseados em
$$(PID) sao previsiveis, convidando condicoes de corrida, sobrescrita e ataques de symlink. O mktemp previne isso por design.
Padroes perigosos a evitar
# RUIM: nome fixo tmpfile=/tmp/myapp.tmp # RUIM: PID e previsivel e colide em execucao concorrente tmpfile=/tmp/myapp.$$
Os problemas:
- Condicao 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 nao intencional - Permissoes expostas: criar via
touchou>depende do umask e pode resultar em arquivo legivel por todos
O que o mktemp corrige
$ tmpfile=$(mktemp) $ stat -c '%a %n' "$tmpfile" 600 /tmp/tmp.A1b2C3d4E5
mktemp realiza criacao e nomeacao como um unico passo indivisivel e falha se o arquivo ja existir. Arquivos sao criados com u+rw (tipicamente 600 apos umask) e diretorios com u+rwx (tipicamente 700), portanto sao exclusivos do dono desde o inicio.
Enquanto o nome for previsivel, um chmod posterior nao pode fechar a janela de corrida. O que importa e que o arquivo seja seguro no momento da criacao.
Como Criar Arquivos e Diretorios Temporarios?
Conclusao: Use
mktemppara um arquivo emktemp -dpara um diretorio; capture o caminho retornado em uma variavel e use essa variavel dali em diante.
Arquivo temporario
$ tmpfile=$(mktemp) $ echo "data" > "$tmpfile" $ cat "$tmpfile" data
Diretorio temporario
$ tmpdir=$(mktemp -d) $ echo "$tmpdir" /tmp/tmp.Xy9Zq2Lk7P
-d (--directory) cria um diretorio em vez de um arquivo. Use quando precisar de varios arquivos intermediarios em um so lugar, e depois limpe com um unico rm -rf "$tmpdir".
Sempre coloque a variavel entre aspas duplas ("$tmpfile"). Isso continua funcionando mesmo se TMPDIR apontar para um caminho contendo espacos.
Como Controlar a Localizacao e o Nome?
Conclusao: Um template molda o nome,
-pdefine o diretorio base, e--suffixadiciona uma extensao. O template precisa de pelo menos tresXs consecutivos no final.
Passar um template
$ mktemp myapp.XXXXXX myapp.k3Df9a
Os Xs sao substituidos por caracteres aleatorios. O GNU requer pelo menos tres Xs consecutivos no ultimo componente.
Definir o diretorio base (-p / --tmpdir)
$ mktemp -p /var/tmp myapp.XXXXXX /var/tmp/myapp.q7Zb2K
-p DIR (--tmpdir[=DIR]) define o diretorio base. Como /tmp pode ser limpo na reinicializacao, escolha /var/tmp para dados temporarios que devem persistir um pouco mais.
Adicionar uma extensao (--suffix)
$ mktemp --suffix=.log myapp.XXXXXX myapp.a8Kd2p.log
Util quando uma ferramenta detecta o formato pela extensao. SUFF nao pode conter uma barra.
Template vs -p / -t (notas)
- Com
-p DIR, o template nao deve ser absoluto. Ele pode conter barras, masmktempcria apenas o componente final. -t("tratar o template como um unico componente de nome de arquivo sob$TMPDIRetc.") e uma opcao mais antiga, agora descontinuada. Use-pem novos scripts.
Como Limpar de Forma Confiavel em um Script?
Conclusao: Adicione
trap 'rm -rf "$tmpdir"' EXITlogo apos a criacao, e os dados temporarios serao removidos tanto em saidas normais quanto em saidas por erro.
O padrao padrao para um script que cria arquivos temporarios:
#!/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
trapimediatamente aposmktemp -d(escreva criacao e limpeza juntas) - Capturar
EXITsignifica que a limpeza executa mesmo quandoset -eaborta no meio - Um unico diretorio permite fazer
rm -rfem tudo, independente de quantos arquivos voce adicionar
Veja Tratamento de Sinais e Limpeza com trap para detalhes.
Limite o alvo do trap a $tmpdir (o caminho unico que mktemp retornou). Um script que faz rm -rf em um padrao amplo como /tmp/* e um acidente esperando para acontecer.
Opcoes e Armadilhas que Vale Conhecer
Conclusao:
-u(dry-run) apenas imprime um nome sem criar nada, quebrando a garantia de seguranca. Use omktempsimples por padrao, que cria o arquivo para voce.
| Opcao | Significado | Cuidado |
|---|---|---|
-d |
Criar um diretorio, nao um arquivo | Limpe com rm -rf |
-u |
Apenas imprimir um nome, nao criar (dry-run) | Abre a janela de corrida. Evite. |
-q |
Suprimir diagnosticos de falha na criacao | Quando o script trata erros por conta propria |
-p DIR |
Definir o diretorio base | Template nao pode ser absoluto |
--suffix=SUFF |
Adicionar uma extensao, etc. | Barra nao permitida |
Pegar um nome de -u e fazer touch voce mesmo anula o proposito do mktemp. Deixe o mktemp cuidar de tudo, desde a criacao ate retornar o nome.
Observe tambem 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