Jak utworzyć katalog tymczasowy?

229

Używam do tworzenia tempfile, usuwania i ponownego tworzenia jako katalogu:

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

Problem w tym, że inny proces może otrzymać tę samą nazwę X, jeśli przypadkowo wykona plik tymczasowy po jednym procesie rm -f Xi tuż przed nim mkdir X.

Xiè Jìléi
źródło

Odpowiedzi:

341

Zastosowanie mktemp -d. Tworzy katalog tymczasowy o losowej nazwie i upewnia się, że plik jeszcze nie istnieje. Trzeba jednak pamiętać o usunięciu katalogu po jego użyciu.

moinudin
źródło
25
Musiałem użyćmktemp -d -t <prefix>
Heath Borders
17
To jest sprawa OS X vs. Linux. Zobacz to pytanie dla wersji, która działa zarówno na: unix.stackexchange.com/questions/30091/...
jwhitlock
2
Zobacz też odpowiedź poniżej autorstwa Ortwina, ponieważ zapewnia to również czyszczenie.
Mathiasdm
5
Dlaczego mówisz „Musisz pamiętać o usunięciu katalogu po jego użyciu”. Czy to nie przeczy celowi korzystania z katalogu tymczasowego?
MK Safi
73

Aby uzyskać bardziej niezawodne rozwiązanie, używam czegoś takiego jak poniżej. W ten sposób katalog tymczasowy będzie zawsze usuwany po zakończeniu skryptu.

Funkcja czyszczenia jest wykonywana na EXITsygnale. To gwarantuje, że funkcja czyszczenia jest zawsze wywoływana, nawet jeśli skrypt gdzieś przerywa.

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

Katalog skryptu bash stąd .

Pułapki Bash .

Ortwin Angermeier
źródło
26
FreeBSD Uwaga! mktemp na FreeBSD nie posiada opcję -p, i cleanupbędą rm -rf aktualny katalog!
szaleniec,
1
Dobrze, zaktualizowałem skrypt, aby sprawdzić, czy można utworzyć katalog tymczasowy.
Ortwin Angermeier
1
@madfriend naprawdę? jeśli się mktempnie powiedzie, WORK_DIRbędzie puste, co oznacza, że ​​polecenie po prostu nie byłoby rm -rfargumentów. Nie używam FreeBSD, ale byłbym bardzo zaskoczony, gdyby rm -rfbył równoważnyrm -rf .
jbg
@ jbg tak, teraz wydaje mi się to również dziwne - to nie powinien być naprawdę duży problem. Być może poprawiłem starą wersję tego skryptu, aby ścieżka do katalogu tymczasowego została obliczona w stosunku do bieżącego katalogu, co spowodowało usunięcie <s> wyginięcia ludzkości </s> z bieżącego katalogu.
szaleniec
1
Aby to poprawić, możesz uniknąć pustego katalogu lub przynajmniej rozwiązać problem w katalogu, korzystając z rozwiązania, w którym: 1. TMPWORKDIR=$(basename 'mktemp -d -p /tmp/git/')a następnie 2 rmdir /tmp/git/"${TMPWORKDIR}".. Jeśli zmienna jest teraz pusta, nadal będziesz wracał do /tmp/git/całego systemu. Rozważ coś takiego w odpowiedzi i chętnie się zgodzę. ;)
Dr Beco
64

Moim ulubionym do tego celu jest

cd $(mktemp -d)
Emmett Butler
źródło
10
i rm $(pwd)? : P
Arran Cudbard-Bell
19
przydatne również: pushd $(mktemp -d)...popd
Ponkadoodle,
4
@ ArranCudbard-Bell powinien byćrm -r $(pwd)
skarbonka
31
@piggybox Szczerze mówiąc, byłbym bardzo ostrożny w użyciu rm -r $(pwd). Rozważ możliwość, że utworzenie katalogu tymczasowego nie powiedzie się z jakiegokolwiek powodu (może system plików / tmp jest pełny lub został ponownie zamontowany tylko do odczytu z powodu błędu?); następnie cd $(mktemp -d)oceni, cdktóre zmiany w katalogu osobistym użytkownika zostaną następnie usunięte.
Jules
1
Może być bezpiecznieif pushd $(mktemp -d || echo BADMPDIR); then ........ ; rm -r $(pwd); popd; fi
AndreyS Scherbakov
9

Poniższy fragment kodu bezpiecznie utworzy katalog tymczasowy ( -d) i zapisze jego nazwę w katalogu TMPDIR. (Przykładowe użycie TMPDIRzmiennej pokazano później w kodzie, w którym jest ona używana do przechowywania oryginalnych plików, które zostaną ewentualnie zmodyfikowane).

Pierwszy trapwiersz wykonuje exit 1polecenie po odebraniu dowolnego z określonych sygnałów . Druga traplinia usuwa (czyści) $TMPDIRwyjście z programu (zarówno normalne, jak i nienormalne). Inicjujemy te pułapki po sprawdzeniu, czy mkdir -dudało się uniknąć przypadkowego uruchomienia pułapki wyjścia $TMPDIRw nieznanym stanie.

#!/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
źródło
1
Chociaż jest to interesujące rozwiązanie do obsługi błędów, nieco więcej wyjaśnienia zalet i możliwych wad byłoby miło.
Murphy
1.) -dsprawdza katalogi. 2.) Terminacja jest już domyślna dla tych sygnałów.
Ceving