Comment créer un répertoire temporaire?

229

J'utilise pour créer un tempfile, le supprimer et le recréer en tant que répertoire:

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

Le problème est qu'un autre processus peut avoir le même nom Xs'il exécute accidentellement le fichier temporaire après un processus rm -f Xet juste avant mkdir X.

Xiè Jìléi
la source

Réponses:

341

Utilisez mktemp -d. Il crée un répertoire temporaire avec un nom aléatoire et s'assure que le fichier n'existe pas déjà. Vous devez cependant vous rappeler de supprimer le répertoire après l'avoir utilisé.

moinudin
la source
25
Je devais utilisermktemp -d -t <prefix>
Heath Borders
17
C'est une chose OS X vs Linux. Voir cette question pour une version qui fonctionne sur les deux: unix.stackexchange.com/questions/30091/…
jwhitlock
2
Voir également la réponse ci-dessous par Ortwin, car cela garantit que le nettoyage est également effectué.
Mathiasdm
5
Pourquoi dites-vous "Vous devez vous rappeler de supprimer le répertoire après l'avoir utilisé."? Cela ne va-t-il pas un peu à l'encontre de l'objectif d'utiliser un répertoire temporaire?
MK Safi
73

Pour une solution plus robuste, j'utilise quelque chose comme ce qui suit. De cette façon, le répertoire temp sera toujours supprimé après la fin du script.

La fonction de nettoyage est exécutée sur le EXITsignal. Cela garantit que la fonction de nettoyage est toujours appelée, même si le script abandonne quelque part.

#!/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
...

Répertoire du script bash d' ici .

Pièges à coups .

Ortwin Angermeier
la source
26
FreeBSD Attention! mktemp sur FreeBSD n'a pas l' option -p, et cleanupsera rm -rf votre répertoire courant!
madfriend
1
Bon point, mise à jour du script pour vérifier si le répertoire temporaire peut être créé.
Ortwin Angermeier
1
@madfriend vraiment? en cas d' mktempéchec, WORK_DIRsera vide, ce qui signifie que la commande serait juste rm -rfsans argument. Je n'utilise pas FreeBSD mais je serais assez surpris s'il rm -rfétait équivalent àrm -rf .
jbg
@jbg oui, cela me semble étrange maintenant aussi - cela ne devrait pas être un très gros problème. J'aurais peut-être modifié une ancienne version de ce script afin qu'un chemin vers le répertoire temporaire soit calculé par rapport au répertoire actuel, entraînant la suppression de <s> l'extinction de l'humanité </s> du répertoire actuel.
madfriend
1
Pour le rendre meilleur, vous pouvez éviter un répertoire vide ou au moins contenir le problème dans un répertoire en utilisant une solution où vous faites: 1. TMPWORKDIR=$(basename 'mktemp -d -p /tmp/git/')puis 2 rmdir /tmp/git/"${TMPWORKDIR}".. Si la variable est vide maintenant, vous reviendrez toujours à /tmp/git/pas à l'ensemble du système. Considérez quelque chose comme ça dans la réponse et je serai heureux d'être d'accord. ;)
Dr Beco
64

Mon one-liner préféré pour cela est

cd $(mktemp -d)
Emmett Butler
la source
10
et rm $(pwd)? : P
Arran Cudbard-Bell
19
également utile: pushd $(mktemp -d)...popd
Ponkadoodle
4
@ ArranCudbard-Bell devrait êtrerm -r $(pwd)
piggybox
31
@piggybox Franchement, je serais très prudent à utiliser rm -r $(pwd). Considérez la possibilité que la création de répertoire temporaire échoue pour une raison quelconque (peut-être que le système de fichiers / tmp est plein ou a été remonté en lecture seule en raison d'une erreur?); puis cd $(mktemp -d)évaluera à ce cdqui change dans le répertoire de l'utilisateur, qui serait ensuite supprimé.
Jules
1
Il peut être en sécurité avecif pushd $(mktemp -d || echo BADMPDIR); then ........ ; rm -r $(pwd); popd; fi
AndreyS Scherbakov
9

L'extrait suivant créera en toute sécurité un répertoire temporaire ( -d) et stockera son nom dans le TMPDIR. (Un exemple d'utilisation de TMPDIRvariable est présenté plus loin dans le code où il est utilisé pour stocker des fichiers originaux qui seront éventuellement modifiés.)

La première trapligne exécute la exit 1commande lorsqu'un des signaux spécifiés est reçu. La deuxième trapligne supprime (nettoie) la $TMPDIRsortie du programme activé (à la fois normale et anormale). Nous initialisons ces pièges après avoir vérifié qu'ils ont mkdir -dréussi à éviter d'exécuter accidentellement le piège de sortie $TMPDIRdans un état inconnu.

#!/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
la source
1
Bien que ce soit une solution intéressante pour la gestion des erreurs, un peu plus d'explications sur les avantages et les éventuelles lacunes seraient bien.
Murphy
1.) -dvérifie les répertoires. 2.) La terminaison est déjà la valeur par défaut pour ces signaux.
ceving