mktemp - простое создание безопасных временных файлов в Linux

Команда mktemp в Linux создаёт временные файлы и каталоги с уникальными, непредсказуемыми именами, что является самым безопасным способом работы с временными данными в скриптах оболочки и системных задачах.

Большинство скриптов оболочки, которые вы найдете в Интернете, создают временные файлы с именами типа /tmp/mydata.txt или /tmp/backup-$$.log, что работает до тех пор, пока не запустятся две копии скрипта одновременно, или пока злонамеренный пользователь не угадает имя файла и не создаст символьную ссылку в /tmp, указывающую на /etc/passwd. Внезапно ваш безобидный скрипт начинает перезаписывать системные файлы, и у вас появляется реальная проблема.

Решением является mktemp — небольшая утилита, которая создает файл или каталог с гарантированно уникальным именем и безопасными правами доступа, а затем возвращает вам путь к нему. Каждый серьезный скрипт системного администратора использует её, и как только вы поймёте, как она работает, вы никогда больше не вернётесь к ручному созданию имен временных файлов.

Почему системные администраторы полагаются на mktemp

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

Если два человека запускают один и тот же скрипт резервного копирования и оба пытаются создать /tmp/backup.log, один из них незаметно перезапишет файл другого. Подобные условия гонки являются одним из самых давних источников ошибок в скриптах Unix.

mktemp решает сразу две проблемы. Во-первых, он гарантирует уникальность имени файла, добавляя случайные символы, так что параллельные запуски никогда не конфликтуют. Во-вторых, он создает файл атомарно с правами доступа, установленными на 600, что означает, что только владелец может читать или записывать в него, что блокирует целую категорию атак через символьные ссылки.

Вы найдете mktemp предустановленным в каждом современном дистрибутиве Linux, поскольку он поставляется как часть пакета GNU coreutils. Устанавливать ничего не нужно, и команда работает одинаково в Ubuntu, Debian, RHEL, Rocky Linux и Fedora.

Объяснение базового синтаксиса mktemp

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

mktemp

Вывод:

/tmp/tmp.kJ9mN2xQ8F

Случайное расширение kJ9mN2xQ8F меняется при каждом запуске команды, что и гарантирует уникальность. Теперь вы можете перенаправить вывод скрипта в этот путь, будучи уверенными, что ничто другое в системе не затронет его. Права доступа к новому файлу автоматически устанавливаются на чтение-запись только для вашего пользователя.

Распространенные ошибки новичков

Новые пользователи часто запускают mktemp, а затем забывают сохранить возвращенный путь, что означает, что они теряют след только что созданного файла. Всегда присваивайте вывод переменной, как показано в TMPFILE=$(mktemp), чтобы ваш скрипт мог обратиться к нему позже.

1. Создание временного файла внутри скрипта

Стандартный шаблон в боевых скриптах заключается в том, чтобы сохранить путь в переменной и настроить механизм очистки, чтобы файл удалялся при завершении работы скрипта, даже если он завершится с ошибкой. Этот шаблон из трех строк — самое полезное, что нужно запомнить о mktemp.

TMPFILE=$(mktemp)
trap "rm -f $TMPFILE" EXIT
echo "some data" > $TMPFILE
cat $TMPFILE

Вывод:

some data

Строка trap указывает оболочке запускать rm -f $TMPFILE при выходе из скрипта по любой причине, чтобы в /tmp никогда не оставались заброшенные файлы.

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

Распространенная ошибка новичков: Забыть строку trap — это ошибка номер один, и за несколько недель ваш /tmp заполнится брошенными файлами. Всегда сочетайте mktemp с очисткой в следующей же строке.

Распространенные ошибки новичков

Забыть строку trap — это ошибка номер один, и за несколько недель ваш /tmp заполнится брошенными файлами. Всегда сочетайте mktemp с очисткой в следующей строке.

2. Создание временного каталога с помощью -d

Когда вашему скрипту нужно работать с несколькими файлами, например, извлекать архив tar или подготавливать сборку, вам нужен целый каталог, а не один файл. Флаг -d обрабатывает этот случай и возвращает путь к только что созданному частному каталогу.

TMPDIR=$(mktemp -d)
echo $TMPDIR
ls -ld $TMPDIR

Вывод:

/tmp/tmp.8vX2mNqL4K
drwx------ 2 ravi ravi 4096 Apr 20 10:42 /tmp/tmp.8vX2mNqL4K

Права доступа drwx------ означают, что только ваш пользователь может войти в каталог или просматривать его содержимое, что как раз и нужно для частного рабочего пространства. Очищайте его с помощью rm -rf $TMPDIR в вашем trap вместо простого rm -f, иначе удаление не удастся, поскольку rm без -r отказывается удалять каталоги.

Распространенные ошибки новичков

Использование rm -f на каталоге завершается без ошибок и оставляет каталог на месте. Всегда используйте rm -rf при очистке каталога, созданного с помощью mktemp -d.

3. Используйте пользовательский шаблон для понятных имен

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

mktemp backup-log-XXXXXX

Вывод:

backup-log-a8K2mQ

Обратите внимание, что файл был создан в текущем каталоге, а не в /tmp, поскольку шаблон не содержал полного пути. Это удивляет многих при первом знакомстве. Чтобы заставить файл создаваться в /tmp независимо от места выполнения скрипта, объедините шаблон с флагом -t, показанным в следующем примере.

Распространенные ошибки новичков

Использование менее трех символов X приводит к ошибке, подобной mktemp: too few X's in template, поэтому придерживайтесь шести символов X в качестве безопасного значения по умолчанию.

4. Принудительное размещение файлов в /tmp с помощью -t

Флаг -t указывает mktemp разместить файл в каталоге, указанном переменной среды TMPDIR, с переходом на /tmp, если эта переменная не задана. Этот шаблон следует использовать в скриптах, которые вы планируете распространять.

mktemp -t backup-XXXXXX.log

Вывод:

/tmp/backup-a8K2mQ.log

Теперь ваш скрипт учитывает настройку TMPDIR пользователя, что важно в системах, где /tmp имеет небольшой размер или где администраторы перенесли временное хранилище на диск большего объема. Скрипт работает корректно везде без изменений. Именно благодаря этой переносимости -t используется в большинстве инструментов оболочки с открытым исходным кодом.

Распространенные ошибки новичков

Жесткое кодирование /tmp/ в шаблоне сводит на нет смысл использования -t. Пусть mktemp выбирает каталог, чтобы ваш скрипт учитывал системную конфигурацию.

5. Выполните пробный запуск с помощью –dry-run

Иногда вам просто нужно имя, не создавая файл, например, при генерации пути для передачи другой команде, которая сама создаст файл. Флаг --dry-run возвращает безопасное уникальное имя, не затрагивая файловую систему вообще.

mktemp --dry-run -t staging-XXXXXX

Вывод:

/tmp/staging-pL9mK3

Файл /tmp/staging-pL9mK3 ещё не существует, поэтому последующая команда, ожидающая, что файл уже будет на месте, завершится с ошибкой. Используйте --dry-run только в том случае, если следующая команда в вашем конвейере сама создаст путь, например, при распаковке tar в каталог или ssh-keygen записи нового файла ключа.

Распространенная ошибка новичков

Если рассматривать вывод --dry-run как реальный путь к файлу и записывать в него, не создав сначала файл, то получится No such file or directory error. Либо пропустите –-dry-run, либо добавьте после него touch или mkdir.

Наиболее полезные флаги mktemp

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

  • -d – создает каталог вместо файла.
  • -t – помещает файл внутрь $TMPDIR или /tmp.
  • -p DIR – помещает файл в указанный вами каталог.
  • -u или --dry-run – возвращает имя, не создавая ничего.
  • -q – подавляет сообщения об ошибках, что полезно, когда вы сами обрабатываете ошибки.

О флаге -p стоит знать, потому что он позволяет выбрать любой каталог, которым вы управляете, например mktemp -p /var/cache/myapp. Это удобно, когда /tmp смонтирован с помощью noexec и вам нужно записать туда скрипт, или когда вы хотите, чтобы временные данные хранились на конкретном диске с большим объёмом свободного места.

Заключение

Теперь вы знаете, почему вручную сгенерированные имена временных файлов — плохая идея, как mktemp решает проблему с атомарным созданием и безопасными правами доступа, а также пять шаблонов, которые охватывают практически каждый скрипт, который вы когда-либо напишете.

Сочетание mktemp и строки очистки trap — это самая полезная привычка, которую вы можете приобрести для написания надёжных скриптов bash, и она избавит вас от целого класса ошибок, которые очень сложно отследить в производственной среде.

Откройте терминал прямо сейчас и попробуйте применить трёхстрочный шаблон из примера, скопируйте:

TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT; echo test > $TMPFILE; cat $TMPFILE

в скрипт, запустите его, а затем выполните ls /tmp, чтобы убедиться, что файл исчез после завершения работы скрипта. Это одно упражнение научит вас больше, чем чтение десяти справочных страниц по данной теме.

Зарубин Иван Эксперт по Linux и Windows

Парашютист со стажем. Много читаю и слушаю подкасты. Люблю посиделки у костра, песни под гитару и приближающиеся дедлайны. Люблю путешествовать.

Похожие статьи

Комментарии (2)

Автар по умолчанию