Удаление созданных временных файлов в неожиданном bash выходе
Я создаю временные файлы из bash script. Я удаляю их в конце обработки, но поскольку script работает довольно долго, если я убью его или просто CTRL-C во время прогона, временные файлы не удаляются.
Есть ли способ поймать эти события и очистить файлы до завершения выполнения?
Кроме того, существует ли какая-то передовая практика для именования и размещения этих временных файлов?
В настоящее время я не уверен между использованием:
TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...
и
TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...
Или, может быть, есть несколько лучших решений?
Ответы
Ответ 1
Вы можете установить " trap" для выполнения при выходе или с помощью элемента управления-c для очистки.
trap "{ rm -f $LOCKFILE; }" EXIT
В качестве альтернативы, один из моих любимых unix-isms - это открыть файл, а затем удалить его, пока вы все еще открываете его. Файл остается в файловой системе, и вы можете читать и записывать его, но как только ваша программа выйдет, файл исчезнет. Не уверен, как бы вы это делали в bash.
BTW: Один аргумент я дам в пользу mktemp вместо вашего собственного решения: если пользователь ожидает, что ваша программа собирается создавать огромные временные файлы, он может захотеть установить TMPDIR
где-то больше, например /var/TMP. mktemp признает, что ваше ручное решение (второй вариант) этого не делает. Я часто использую TMPDIR=/var/tmp gvim -d foo bar
, например.
Ответ 2
Обычно я создаю каталог для размещения всех моих временных файлов, а затем сразу же после этого создаю обработчик EXIT для очистки этого каталога, когда выйдет script.
MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT
Если вы поместите все свои временные файлы в $MYTMPDIR
, то все они будут удалены, когда ваш script выйдет в большинстве случаев. Убийство процесса с помощью SIGKILL (kill -9) сразу же уничтожает процесс, поэтому ваш обработчик EXIT не будет работать в этом случае.
Ответ 3
Вы хотите использовать команду trap для обработки выхода из script или сигналов типа CTRL-C. Подробнее см. Advanced Bash Scripting Guide.
Для ваших tempfiles рекомендуется использовать basename $0
, а также предоставить шаблон, который предоставляет место для достаточно временных файлов:
tempfile() {
tempprefix=$(basename "$0")
mktemp /tmp/${tempprefix}.XXXXXX
}
TMP1=$(tempfile)
TMP2=$(tempfile)
trap 'rm -f $TMP1 $TMP2' EXIT
Ответ 4
Альтернативой использования прогнозируемого имени файла с $$ является зияющая дыра в безопасности, и вы никогда не должны думать о ее использовании. Даже если это простой персональный script на вашем ПК с одним пользователем. Это очень плохая привычка, которую вы не должны получить. BugTraq заполнен инцидентами "небезопасного временного файла". См. здесь, здесь и здесь для получения дополнительной информации об аспекте безопасности временных файлов.
Я изначально думал о цитировании небезопасных назначений TMP1 и TMP2, но, во-вторых, подумал, что, вероятно, не будет хорошей идеей.
Ответ 5
Просто имейте в виду, что выбранный ответ bashism
, что означает решение как
trap "{ rm -f $LOCKFILE }" EXIT
будет работать только в bash (он не поймает Ctrl + c, если оболочка dash
или классическая sh
), но если вам нужна совместимость, вам все равно нужно перечислить все сигналы, которые вы хотите захватить.
Также имейте в виду, что когда script выходит из ловушки для сигнала "0" (иначе EXIT), всегда выполняется, что приводит к двойному выполнению команды trap
.
Чтобы не выставлять все сигналы в одной строке, если есть сигнал EXIT.
Чтобы лучше понять это, смотрите следующий script, который будет работать в разных системах без изменений:
#!/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 (заключительный этап выход)
Ответ 6
Я предпочитаю использовать tempfile
, который создает файл в /tmp безопасным образом, и вам не нужно беспокоиться о его названии:
tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit
Ответ 7
Вам не нужно беспокоиться об удалении этих файлов tmp, созданных с помощью mktemp. Они будут удалены в любом случае позже.
Используйте mktemp, если можете, поскольку он генерирует более уникальные файлы, а затем префикс $$. И это похоже на более кросс-платформенный способ создания временных файлов, а затем явно помещать их в/tmp.