Удаление созданных временных файлов при неожиданном выходе из bash - PullRequest
80 голосов
/ 26 марта 2009

Я создаю временные файлы из bash-скрипта. Я удаляю их в конце обработки, но поскольку скрипт выполняется довольно долго, если я его убиваю или просто нажимаю CTRL-C во время выполнения, временные файлы не удаляются.
Есть ли способ, как я могу перехватить эти события и очистить файлы до завершения выполнения?

Кроме того, существуют ли какие-либо рекомендации по именованию и расположению этих временных файлов?
В настоящее время я не уверен между использованием:

TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...

и

TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...

Или, может быть, есть лучшие решения?

Ответы [ 7 ]

102 голосов
/ 26 марта 2009

Я обычно создаю каталог для размещения всех моих временных файлов, а затем сразу после этого создаю обработчик EXIT для очистки этого каталога при выходе из сценария.

MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT

Если вы поместите все ваши временные файлы в $MYTMPDIR, то они все будут удалены, когда ваш скрипт завершит работу в большинстве случаев. Уничтожение процесса с помощью SIGKILL (kill -9) сразу же убивает процесс, поэтому ваш обработчик EXIT в этом случае не запустится.

78 голосов
/ 26 марта 2009

Вы можете установить « trap » для выполнения при выходе или на элементе управления c для очистки.

trap "{ rm -f $LOCKFILE; }" EXIT

В качестве альтернативы, один из моих любимых unix-isms - открыть файл, а затем удалить его, пока он еще открыт. Файл остается в файловой системе, и вы можете читать и записывать его, но как только ваша программа завершает работу, файл исчезает. Не уверен, как ты это сделаешь в bash.

Кстати: один аргумент я приведу в пользу mktemp вместо использования вашего собственного решения: если пользователь ожидает, что ваша программа создаст огромные временные файлы, он может захотеть установить TMPDIR где-то больше, например / var / TMP. mktemp признает, что ваше ручное решение (второй вариант) нет. Я часто использую TMPDIR=/var/tmp gvim -d foo bar, например.

20 голосов
/ 26 марта 2009

Вы хотите использовать команду trap для обработки выхода из скрипта или сигналов типа CTRL-C. Подробнее см. Вики Грега .

Для ваших временных файлов рекомендуется использовать basename $0, а также предоставить шаблон, в котором достаточно места для временных файлов:

tempfile() {
    tempprefix=$(basename "$0")
    mktemp /tmp/${tempprefix}.XXXXXX
}

TMP1=$(tempfile)
TMP2=$(tempfile)

trap 'rm -f $TMP1 $TMP2' EXIT
7 голосов
/ 09 января 2017

Просто имейте в виду, что выбранный ответ - bashism, что означает решение как

trap "{ rm -f $LOCKFILE }" EXIT

будет работать только в bash (он не будет перехватывать Ctrl + c, если shell dash или classic sh), но если вы хотите совместимости, вам все равно нужно перечислить все сигналы, которые вы хотите перехватить.

Также имейте в виду, что когда скрипт выходит из ловушки для сигнала «0» (он же EXIT) всегда выполняется, что приводит к двойному выполнению команды trap.

Это причина не складывать все сигналы в одну строку, если есть сигнал EXIT.

Чтобы лучше понять это, посмотрите на следующий скрипт, который будет работать в разных системах без изменений:

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

Это решение даст вам больше контроля, поскольку вы можете запускать часть своего кода при появлении фактического сигнала непосредственно перед окончательным выходом (функция preExit), а при необходимости вы можете запускать некоторый код при фактическом сигнале EXIT (финальная стадия выход)

3 голосов
/ 29 марта 2009

Альтернативой использования предсказуемого имени файла с $$ является дыра в безопасности, и вам никогда не следует думать об ее использовании. Даже если это простой персональный скрипт на вашем однопользовательском ПК. Это очень плохая привычка, которую вы не должны приобретать. BugTraq заполнен инцидентами «небезопасный временный файл». См. здесь , здесь и здесь для получения дополнительной информации об аспекте безопасности временных файлов.

Вначале я думал о цитировании небезопасных назначений TMP1 и TMP2, но со второй мысли это, вероятно, не было бы хорошей идеей .

1 голос
/ 21 июля 2011

Я предпочитаю использовать tempfile, который безопасно создает файл в / tmp, и вам не нужно беспокоиться о его именовании:

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit
0 голосов
/ 26 марта 2009

Вам не нужно беспокоиться об удалении файлов tmp, созданных с помощью mktemp. Они будут удалены в любом случае позже.

Используйте mktemp, если можете, поскольку он генерирует больше уникальных файлов, чем префикс '$$'. И это выглядит как более кроссплатформенный способ создания временных файлов, чем их явное размещение в / tmp.

...