Я создаю временные файлы из сценария bash. Я удаляю их в конце обработки, но так как скрипт работает довольно долго, если я его убью или просто CTRL-C во время запуска, временные файлы не удаляются.
Есть ли способ поймать эти события и очистить файлы до завершения выполнения?
Кроме того, есть ли какая-то передовая практика для именования и расположения этих временных файлов?
В настоящее время я не уверен, использовать ли:
TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...
а также
TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...
Или, может быть, есть лучшие решения?
bash
exit
temporary-files
скинп
источник
источник
Ответы:
Вы можете установить « ловушку » на выполнение при выходе или на Control-c для очистки.
trap "{ rm -f $LOCKFILE; }" EXIT
В качестве альтернативы, один из моих любимых unix-isms - открыть файл, а затем удалить его, пока он еще открыт. Файл остается в файловой системе, и вы можете читать и записывать его, но как только ваша программа завершает работу, файл исчезает. Хотя не знаю, как это сделать в bash.
Кстати: один аргумент, который я приведу в пользу mktemp вместо использования вашего собственного решения: если пользователь ожидает, что ваша программа будет создавать огромные временные файлы, он может захотеть установить
TMPDIR
что-то большее, например / var / tmp. mktemp понимает это, а ваше ручное решение (второй вариант) - нет. ЯTMPDIR=/var/tmp gvim -d foo bar
, например, часто использую .источник
exec 5<>$TMPFILE
связывает дескриптор файла 5 до $ TMPFILE чтения и записи, и вы можете использовать<&5
,>&5
и/proc/$$/fd/5
(Linux) в дальнейшем. Единственная проблема в том, что Bash неseek
работает ...trap
поводу: ловушки нетSIGKILL
(по замыслу, так как выполнение немедленно прекращается). Итак, если это может произойти, разработайте запасной план (например,tmpreaper
). Во-вторых, ловушки не суммируются - если вам нужно выполнить более одного действия, все они должны быть вtrap
команде. Один из способов справиться с несколькими действиями очистки заключается в определении функции (и вы можете переопределить его как ваша программа продолжается, если это необходимо) и ссылка , что:trap cleanup_function EXIT
.trap "rm -f $LOCKFILE" EXIT
иначе я получу неожиданную ошибку конца файла.Обычно я создаю каталог, в который помещаю все мои временные файлы, а затем сразу же после этого создаю обработчик EXIT для очистки этого каталога при выходе из сценария.
MYTMPDIR=$(mktemp -d) trap "rm -rf $MYTMPDIR" EXIT
Если вы поместите все свои временные файлы внутрь
$MYTMPDIR
, то в большинстве случаев они все будут удалены при выходе из сценария. Однако завершение процесса с помощью SIGKILL (kill -9) приводит к немедленному уничтожению процесса, поэтому ваш обработчик EXIT не будет работать в этом случае.источник
Вы хотите использовать команду trap для обработки выхода из сценария или сигналов типа CTRL-C. См. Подробности в Greg's Wiki .
Для ваших
basename $0
временных файлов использование - хорошая идея, так же как и предоставление шаблона, который предоставляет место для достаточного количества временных файлов:tempfile() { tempprefix=$(basename "$0") mktemp /tmp/${tempprefix}.XXXXXX } TMP1=$(tempfile) TMP2=$(tempfile) trap 'rm -f $TMP1 $TMP2' EXIT
источник
$()
. Также добавлены двойные кавычки.tempfile
команда, в то время как все разумные современные системы, о которых я знаю, имеютmktemp
команду.Просто имейте в виду, что выбранный ответ -
bashism
это решение какtrap "{ rm -f $LOCKFILE }" EXIT
будет работать только в bash (он не будет ловить Ctrl + c, если оболочка является
dash
или классической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 (последний этап выхода)источник
Альтернатива использования предсказуемого имени файла с $$ - это зияющая дыра в безопасности, и вам никогда и никогда не следует думать об ее использовании. Даже если это простой персональный скрипт на вашем однопользовательском ПК. Это очень плохая привычка, которой не следует приобретать. BugTraq полон инцидентов, связанных с "небезопасным временным файлом". См. Здесь , здесь и здесь для получения дополнительной информации об аспектах безопасности временных файлов.
Сначала я подумывал процитировать небезопасные назначения TMP1 и TMP2, но, если подумать, это, вероятно, не было бы хорошей идеей .
источник
Я не могу поверить, что так много людей предполагают, что имя файла не будет содержать пробела. Мир рухнет, если $ TMPDIR когда-либо будет назначен «временный каталог».
zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps") trap "rm -f ${zTemp@Q}" EXIT
Пробелы и другие специальные символы, такие как одинарные кавычки и символы возврата каретки в именах файлов, следует рассматривать в коде как требование хорошей привычки программирования.
источник
${parameter@operator}
расширения были добавлены в Bash 4.4 (выпущен в сентябре 2016 г.).trap "rm -f $(printf %q "$zTemp")" EXIT
zTemp
будет изменено позже в сценарии. Кроме того,zTemp
можно объявитьlocal
функцию; это не обязательно должна быть глобальная переменная сценария.Я предпочитаю использовать,
tempfile
который создает файл в / tmp безопасным способом, и вам не нужно беспокоиться о его именовании:tmp=$(tempfile -s "your_sufix") trap "rm -f '$tmp'" exit
источник
Вам не нужно беспокоиться об удалении этих файлов tmp, созданных с помощью mktemp. Они все равно будут удалены позже.
По возможности используйте mktemp, поскольку он генерирует больше уникальных файлов, чем префикс $$. И это похоже на более кроссплатформенный способ создания временных файлов, а затем их явного помещения в / tmp.
источник