Como criar um diretório temporário?

229

Eu uso para criar tempfile, excluir e recriar como um diretório:

tmpnam=`tempfile`
rm -f $tmpnam
mkdir "$tmpnam"

O problema é que outro processo pode ter o mesmo nome X, se executar acidentalmente o tempfile após um processo rm -f Xe pouco antes mkdir X.

Xiè Jìléi
fonte

Respostas:

341

Use mktemp -d. Ele cria um diretório temporário com um nome aleatório e garante que o arquivo ainda não exista. Você precisa se lembrar de excluir o diretório depois de usá-lo.

moinudin
fonte
25
Eu precisava usarmktemp -d -t <prefix>
Heath Borders
17
Isso é coisa do OS X vs Linux. Veja esta pergunta para uma versão que funcione em ambos: unix.stackexchange.com/questions/30091/…
jwhitlock
2
Além disso, veja a resposta abaixo de Ortwin, pois isso garante que a limpeza também seja feita.
Mathiasdm
5
Por que você diz "Você precisa se lembrar de excluir o diretório depois de usá-lo."? Isso meio que anula o propósito de usar um diretório temporário?
MK Safi
73

Para uma solução mais robusta, uso algo como o seguinte. Dessa forma, o diretório temporário sempre será excluído após a saída do script.

A função de limpeza é executada no EXITsinal. Isso garante que a função de limpeza seja sempre chamada, mesmo que o script seja interrompido em algum lugar.

#!/bin/bash    

# the directory of the script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# the temp directory used, within $DIR
# omit the -p parameter to create a temporal directory in the default location
WORK_DIR=`mktemp -d -p "$DIR"`

# check if tmp dir was created
if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then
  echo "Could not create temp dir"
  exit 1
fi

# deletes the temp directory
function cleanup {      
  rm -rf "$WORK_DIR"
  echo "Deleted temp working directory $WORK_DIR"
}

# register the cleanup function to be called on the EXIT signal
trap cleanup EXIT

# implementation of script starts here
...

Diretório do script bash a partir daqui .

Armadilhas Bash .

Ortwin Angermeier
fonte
26
FreeBSD Cuidado! O mktemp no FreeBSD não possui a opção -p, e cleanupirá rm -rf no seu diretório atual!
madfriend
1
Bom ponto, atualizou o script para verificar se o diretório temporário pode ser criado.
Ortwin Angermeier 7/03/2017
1
@madfriend realmente? se mktempfalhar, WORK_DIRestará vazio, o que significa que o comando ficaria rm -rfsem argumento. Não uso FreeBSD, mas eu ficaria muito surpreso se rm -rffoi equivalente arm -rf .
jbg
@ jbg sim, parece estranho para mim agora também - não deve ser um problema muito grande. Eu poderia ter ajustado uma versão antiga desse script para que um caminho para o diretório temporário fosse calculado relativamente ao diretório atual, resultando na <s> extinção da remoção do diretório atual da humanidade </s>.
madfriend
1
Para torná-lo melhor, você pode evitar um diretório vazio ou pelo menos conter o problema em um diretório usando uma solução onde você faz: 1. TMPWORKDIR=$(basename 'mktemp -d -p /tmp/git/')e depois 2 rmdir /tmp/git/"${TMPWORKDIR}".. Se a variável estiver vazia agora, você ainda retornará /tmp/git/para o sistema inteiro. Considere algo assim na resposta e eu concordarei com prazer. ;)
Beco Dr Juno
64

Minha frase favorita para isso é

cd $(mktemp -d)
Emmett Butler
fonte
10
e rm $(pwd)? : P
Arran Cudbard-Bell
19
Também útil: pushd $(mktemp -d)...popd
Ponkadoodle
4
@ ArranCudbard-Bell deve serrm -r $(pwd)
piggybox
31
@ piggybox Francamente, eu seria muito cauteloso de usar rm -r $(pwd). Considere a possibilidade de a criação temporária de diretórios falhar por qualquer motivo (talvez o sistema de arquivos / tmp esteja cheio ou tenha sido remontado somente para leitura devido a um erro?); em seguida cd $(mktemp -d), avaliará cdquais alterações no diretório inicial do usuário serão excluídas posteriormente.
Jules
1
Pode ser seguro comif pushd $(mktemp -d || echo BADMPDIR); then ........ ; rm -r $(pwd); popd; fi
AndreyS Scherbakov
9

O seguinte snippet criará com segurança um diretório temporário ( -d) e armazenará seu nome no diretório TMPDIR. (Um exemplo de uso de TMPDIRvariável é mostrado posteriormente no código em que é usado para armazenar arquivos originais que possivelmente serão modificados.)

A primeira traplinha executa o exit 1comando quando qualquer um dos sinais especificados é recebido. A segunda traplinha remove (limpa) a $TMPDIRsaída do programa (normal e anormal). Inicializamos esses traps depois de verificarmos se mkdir -dfoi possível executar acidentalmente o trap de saída com $TMPDIRum estado desconhecido.

#!/bin/bash

# Create a temporary directory and store its name in a variable ...
TMPDIR=$(mktemp -d)

# Bail out if the temp directory wasn't created successfully.
if [ ! -e $TMPDIR ]; then
    >&2 echo "Failed to create temp directory"
    exit 1
fi

# Make sure it gets removed even if the script exits abnormally.
trap "exit 1"           HUP INT PIPE QUIT TERM
trap 'rm -rf "$TMPDIR"' EXIT

# Example use of TMPDIR:
for f in *.csv; do
    cp "$f" "$TMPDIR"
    # remove duplicate lines but keep order
    perl -ne 'print if ++$k{$_}==1' "$TMPDIR/$f" > "$f"
done
jreisinger
fonte
1
Embora esta seja uma solução interessante para o tratamento de erros, seria um pouco mais explícita das vantagens e possíveis deficiências.
Murphy
1.) -dverifica se há diretórios. 2.) A terminação já é o padrão para esses sinais.
ceving 10/03