Tworzę pliki tymczasowe ze skryptu bash. Usuwam je pod koniec przetwarzania, ale skoro skrypt działa dość długo, jeśli go zabiję lub po prostu CTRL-C w trakcie działania, pliki tymczasowe nie są usuwane.
Czy istnieje sposób, w jaki mogę przechwycić te zdarzenia i wyczyścić pliki przed zakończeniem wykonywania?
Czy jest też jakaś najlepsza praktyka dotycząca nazewnictwa i lokalizacji tych plików tymczasowych?
Obecnie nie jestem pewien między użyciem:
TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...
i
TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...
A może są jakieś lepsze rozwiązania?
bash
exit
temporary-files
skinp
źródło
źródło
Odpowiedzi:
Możesz ustawić " pułapkę " do wykonania przy wyjściu lub na control-c w celu wyczyszczenia.
trap "{ rm -f $LOCKFILE; }" EXIT
Alternatywnie, jednym z moich ulubionych unix-izmów jest otwarcie pliku, a następnie usunięcie go, gdy nadal jest otwarty. Plik pozostaje w systemie plików i możesz go czytać i zapisywać, ale gdy tylko program kończy pracę, plik znika. Nie jestem jednak pewien, jak to zrobiłbyś w bashu.
BTW: Jeden argument, który podam na korzyść mktemp zamiast używania własnego rozwiązania: jeśli użytkownik przewiduje, że twój program będzie tworzył ogromne pliki tymczasowe, może chcieć ustawić
TMPDIR
coś większego, na przykład / var / tmp. mktemp rozpoznaje to, ale Twoje ręcznie tworzone rozwiązanie (druga opcja) nie. Na przykład często używamTMPDIR=/var/tmp gvim -d foo bar
.źródło
exec 5<>$TMPFILE
plik krawaty deskryptor 5 do $ tmpfile jak odczytu i zapisu, a można użyć<&5
,>&5
oraz/proc/$$/fd/5
(Linux) później. Jedynym problemem jest to, że Bashowi brakujeseek
funkcji ...trap
: nie ma sposobu na pułapkęSIGKILL
(zgodnie z projektem, ponieważ natychmiast kończy wykonywanie). Więc jeśli tak się stanie, miej plan awaryjny (taki jaktmpreaper
). Po drugie, pułapki nie kumulują się - jeśli masz więcej niż jedną akcję do wykonania, wszystkie muszą znajdować się wtrap
dowództwie. Jednym ze sposobów radzenia sobie z wieloma działań porządkowych jest zdefiniowanie funkcji (i można zdefiniować ją jako swoich wpływów programu, jeśli to konieczne) i odniesienia, który:trap cleanup_function EXIT
.trap "rm -f $LOCKFILE" EXIT
lub otrzymałem nieoczekiwany błąd końca pliku.Zwykle tworzę katalog, w którym umieszczam wszystkie moje pliki tymczasowe, a następnie natychmiast po utworzeniu programu obsługi EXIT, aby wyczyścić ten katalog po zakończeniu działania skryptu.
MYTMPDIR=$(mktemp -d) trap "rm -rf $MYTMPDIR" EXIT
Jeśli umieścisz wszystkie pliki tymczasowe pod
$MYTMPDIR
, w większości przypadków zostaną one usunięte po zamknięciu skryptu. Zabicie procesu za pomocą SIGKILL (kill -9) zabija proces od razu, więc twoja obsługa EXIT nie będzie działać w tym przypadku.źródło
Chcesz użyć polecenia trap do obsługi wyjścia ze skryptu lub sygnałów, takich jak CTRL-C. Zobacz wiki Grega po szczegóły.
W przypadku
basename $0
plików tymczasowych dobrym pomysłem jest użycie , a także zapewnienie szablonu, który zapewnia wystarczającą liczbę plików tymczasowych:tempfile() { tempprefix=$(basename "$0") mktemp /tmp/${tempprefix}.XXXXXX } TMP1=$(tempfile) TMP2=$(tempfile) trap 'rm -f $TMP1 $TMP2' EXIT
źródło
$()
. Dodano również podwójne cudzysłowy.tempfile
polecenie, podczas gdy wszystkie rozsądne nowoczesne systemy, które znam, mająmktemp
polecenie.Pamiętaj tylko, że wybrana odpowiedź to
bashism
, co oznacza rozwiązanie jakotrap "{ rm -f $LOCKFILE }" EXIT
działałby tylko w bashu (nie złapie Ctrl + c, jeśli shell jest
dash
lub klasycznysh
), ale jeśli chcesz kompatybilności, nadal musisz wyliczyć wszystkie sygnały, które chcesz przechwycić.Należy również pamiętać, że kiedy skrypt wychodzi z pułapki na sygnał "0" (aka EXIT) jest zawsze wykonywany, co skutkuje podwójnym wykonaniem
trap
polecenia.To powód, aby nie układać wszystkich sygnałów w jednej linii, jeśli jest sygnał EXIT.
Aby lepiej to zrozumieć, spójrz na następujący skrypt, który będzie działał w różnych systemach bez zmian:
#!/bin/sh on_exit() { echo 'Cleaning up...(remove tmp files, etc)' } on_preExit() { echo echo 'Exiting...' # Runs just before actual exit, # shell will execute EXIT(0) after finishing this function # that we hook also in on_exit function exit 2 } trap on_exit EXIT # EXIT = 0 trap on_preExit HUP INT QUIT TERM STOP PWR # 1 2 3 15 30 sleep 3 # some actual code... exit
To rozwiązanie da ci większą kontrolę, ponieważ możesz uruchomić część kodu na wystąpieniu rzeczywistego sygnału tuż przed końcowym wyjściem (
preExit
funkcja), a jeśli to konieczne, możesz uruchomić kod na rzeczywistym sygnale EXIT (końcowy etap wyjścia)źródło
Alternatywą użycia przewidywalnej nazwy pliku z $$ jest ziejąca luka w zabezpieczeniach i nigdy, przenigdy nie powinieneś myśleć o jej użyciu. Nawet jeśli jest to zwykły osobisty skrypt na komputerze jednego użytkownika. Jest to bardzo zły nawyk, którego nie powinieneś nabywać. BugTraq jest pełen incydentów związanych z "niebezpiecznymi plikami tymczasowymi". Zobacz tutaj , tutaj i tutaj, aby uzyskać więcej informacji na temat aspektu bezpieczeństwa plików tymczasowych.
Początkowo myślałem o zacytowaniu niezabezpieczonych przypisań TMP1 i TMP2, ale po zastanowieniu prawdopodobnie nie byłby to dobry pomysł .
źródło
Nie mogę uwierzyć, że tak wiele osób zakłada, że nazwa pliku nie będzie zawierała spacji. Świat się załamie, jeśli $ TMPDIR zostanie kiedykolwiek przypisany do „katalogu tymczasowego”.
zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps") trap "rm -f ${zTemp@Q}" EXIT
Spacje i inne znaki specjalne, takie jak apostrofy i znaki powrotu karetki w nazwach plików, powinny być traktowane w kodzie jako wymóg przyzwoitego nawyku programowania.
źródło
${parameter@operator}
rozszerzenia zostały dodane w Bash 4.4 (wydany we wrześniu 2016 r.).trap "rm -f $(printf %q "$zTemp")" EXIT
zTemp
późniejszych zmian w skrypcie. Ponadto,zTemp
może być uznanalocal
do funkcji; nie musi to być globalna zmienna skryptu.Wolę używać,
tempfile
który tworzy plik w / tmp w bezpieczny sposób i nie musisz martwić się o jego nazewnictwo:tmp=$(tempfile -s "your_sufix") trap "rm -f '$tmp'" exit
źródło
Nie musisz martwić się usuwaniem tych plików tmp utworzonych za pomocą mktemp. I tak zostaną później usunięte.
Jeśli możesz, użyj mktemp, ponieważ generuje on więcej unikalnych plików niż prefiks „$$”. Wygląda na bardziej wieloplatformowy sposób tworzenia plików tymczasowych, a następnie jawne umieszczanie ich w / tmp.
źródło