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

StackOverflow https://stackoverflow.com/questions/687014

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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

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

и

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

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

Это было полезно?

Решение

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

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

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

КСТАТИ:Один аргумент, который я приведу в пользу 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.Смотрите на Вики Грега для получения подробной информации.

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

tempfile() {
    tempprefix=$(basename "$0")
    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" (он же EXIT), что приводит к двойному выполнению trap команда.

Это причина не складывать все сигналы в одну строку, если есть сигнал ВЫХОДА.

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

#!/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 функция) и если это необходимо, вы можете запустить некоторый код при фактическом сигнале ВЫХОДА (заключительная стадия выхода)

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top