Удаление созданных временных файлов при неожиданном выходе из bash


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

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

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

и

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

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

7 63

7 ответов:

вы можете задать "ловушка " выполнить на выходе или на элементе управления-c, чтобы очистить.

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

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

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

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

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

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

вы хотите использовать ловушка команда для обработки выхода из скрипта или сигналов, таких как CTRL-C. см.Advanced Bash Scripting Guide для сведения.

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

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

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

trap 'rm -f $TMP1 $TMP2' EXIT

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

trap "{ rm -f $LOCKFILE }" EXIT

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

также имейте в виду, что когда скрипт выходит из ловушки для сигнала "0"(aka EXIT) всегда выполняется в результате двойного выполнения

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

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

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

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit

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

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