Имена файлов удаляются с помощью системных вызовов unlink, unlinkat.

Ну дак вот. Когда счетчик ссылок (имен) становится равен нулю — файл удаляется.

Физическое удаление (блоки маркируются свободными) происходит когда больше никто не удерживает файл. То есть процесс закрыл последний дескриптор ассоциированный с файлом.

Давай попробуем поймать (открыть файл) до того, как запустится вызов unlink.

Создаем искусственный временный файл:

printf '%s\n' {a..z} > /tmp/sh-thd-bashdays

Создаем и запускаем скрипт:

#!/bin/bash

file=/tmp/sh-thd-bashdays
exec 3< "$file"
rm -vf "$file"      # Имени уже нет
read -N 4096 -ru 3  # Но мы читаем
printf '%s' $REPLY  # Выводим
exec 3>&-
exit

Что тут происходит?

exec 3< - файл открывается на чтение, привязывается к дескриптору 3 и с этого момента файл начинает жить в «памяти» в open file table ядра, даже если мы его ёбнем удалим. Дескриптор 3 теперь указывает на открытый файл, независимо от имени.

rm -vf - файл удаляется из файловой системы, имени больше нет, НО, его содержимое еще доступно, потому что он открыт.

read -N 4096 - читаем до 4096 байт из открытого файла через дескриптор 3.

exec 3>&- - закрываем дескриптор 3 и после этого файл окончательно исчезнет, если его больше никто не держит, а ядро высвобождает ресурсы.

Итоги:

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

Это классическая Unix-модель: имя файла — не сам файл, а просто ссылка.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Если держишь дескриптор — файл всё ещё существует.

А тут как-то рассказывал, как восстанавливать удаленные файлы, в том числе и запущенные.

Чтиво почитать:

man 2 unlink

man 2 unlinkat