¿Cómo crear un directorio temporal?

229

Yo uso para crear un tempfile, eliminarlo y volver a crearlo como un directorio:

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

El problema es que otro proceso puede obtener el mismo nombre Xsi accidentalmente ejecuta tempfile después de un proceso rm -f Xy justo antes mkdir X.

Xiè Jìléi
fuente

Respuestas:

341

Uso mktemp -d. Crea un directorio temporal con un nombre aleatorio y se asegura de que el archivo no exista. Sin embargo, debe recordar eliminar el directorio después de usarlo.

moinudin
fuente
25
Tuve que usarmktemp -d -t <prefix>
Heath Borders
17
Esto es algo de OS X vs Linux. Consulte esta pregunta para obtener una versión que funciona en ambos: unix.stackexchange.com/questions/30091/…
jwhitlock
2
Además, vea la respuesta a continuación de Ortwin, ya que eso asegura que la limpieza también se realice.
Mathiasdm el
55
¿Por qué dice "Sin embargo, debe recordar eliminar el directorio después de usarlo"? ¿No es eso algo que anula el propósito de usar un directorio temporal?
MK Safi
73

Para una solución más robusta, uso algo como lo siguiente. De esa forma, el directorio temporal siempre se eliminará después de que salga el script.

La función de limpieza se ejecuta en la EXITseñal. Eso garantiza que siempre se llama a la función de limpieza, incluso si el script aborta en alguna parte.

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

Directorio de script bash desde aquí .

Bash trampas .

Ortwin Angermeier
fuente
26
¡Atención FreeBSD! mktemp en FreeBSD no tiene opción -p, y cleanupserá rm-rf su directorio actual!
Madfriend
1
Buen punto, actualicé el script para verificar si se podía crear el directorio temporal.
Ortwin Angermeier
1
@madfriend realmente? si mktempfalla, WORK_DIRestará vacío, lo que significa que el comando simplemente no tendrá rm -rfargumento. No uso FreeBSD pero estaría bastante sorprendido si rm -rffuera equivalente arm -rf .
jbg
@jbg sí, ahora también me parece extraño, no debería ser un gran problema. Podría haber modificado una versión anterior de este script para que se calculara una ruta al directorio temporal en relación con el directorio actual, lo que resultaría en la <s> extinción de la humanidad </s> la eliminación actual del directorio.
madfriend
1
Para mejorarlo, puede evitar un directorio vacío o al menos contener el problema dentro de un directorio utilizando una solución donde lo haga: 1. TMPWORKDIR=$(basename 'mktemp -d -p /tmp/git/')y luego 2 rmdir /tmp/git/"${TMPWORKDIR}".. Si la variable está vacía ahora, aún no recurrirá /tmp/git/a todo el sistema. Considere algo como esto en la respuesta y con mucho gusto estaré de acuerdo. ;)
Dr Beco
64

Mi frase favorita para esto es

cd $(mktemp -d)
Emmett Butler
fuente
10
y rm $(pwd)? : P
Arran Cudbard-Bell
19
también útil: pushd $(mktemp -d)...popd
Ponkadoodle
44
@ ArranCudbard-Bell debería estarrm -r $(pwd)
piggybox
31
@piggybox Francamente, sería muy cauteloso de usar rm -r $(pwd). Considere la posibilidad de que la creación de directorio temporal falle por cualquier razón (¿tal vez el sistema de archivos / tmp está lleno o se ha vuelto a montar de solo lectura debido a un error?); luego cd $(mktemp -d)evaluará a cdqué cambios en el directorio de inicio del usuario, que posteriormente se eliminarán.
Julio
1
Puede ser seguro conif pushd $(mktemp -d || echo BADMPDIR); then ........ ; rm -r $(pwd); popd; fi
AndreyS Scherbakov
9

El siguiente fragmento creará de forma segura un directorio temporal ( -d) y almacenará su nombre en TMPDIR. (Un ejemplo de uso deTMPDIR variable se muestra más adelante en el código donde se usa para almacenar archivos originales que posiblemente se modificarán).

La primera traplínea ejecuta el exit 1comando cuando se recibe cualquiera de las señales especificadas . La segunda traplínea elimina (limpia) la $TMPDIRsalida del programa (tanto normal como anormal). Inicializamos estas trampas después de comprobar que se mkdir -dlogró evitar accidentalmente ejecutar la trampa de salida $TMPDIRen un estado desconocido.

#!/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
fuente
1
Si bien esta es una solución interesante para el manejo de errores, un poco más de explicación de las ventajas y posibles deficiencias sería bueno.
Murphy
1.) -dbusca directorios. 2.) La terminación ya es el valor predeterminado para esas señales.
ceving