1) Посмотреть список всех удаленных файлов с открытыми файловыми дескрипторами можно командой
lsof | grep deleted
В выводе мы получим записи вида
nginx 4403 4430 nginx 29w REG 8,1 5779197 165960 /tmp/access.log (deleted)
Восьмая колонка в восьмой колонке мы можем увидеть размер файла в байтах, но нас интересует расположение файлового дескриптора, чтобы первая часть пути к нему это вторая колонка вывода, в данном случаи 4403
2) Найдем полный путь до дескриптора
Выполним команду ниже подставив 4403 после /proc/ и имя файла в паттерн grep
ls -l /proc/4403/fd | grep "/tmp/access.log"
Вывод команды должен выглядеть примерно так:
l-wx------ 1 nginx nginx 64 Oct 30 15:21 29 -> /tmp/access.log (deleted)
Тут мы видим вторую часть пути это 9ая колонка, цифра 29
В итоге полный путь до файлового дескриптора удаленного файла выглядит так:
/proc/4403/fd/29
Также путь до файла для очистки можно получить используя следующую команду (несколько итераций awk используется для дополнительной валидации)
find /proc/*/fd -ls 2> /dev/null | grep '(deleted)' | sed 's#\ (deleted)##g' | awk '{print $11" "$13}' | sort -u -k 2 | grep "/tmp/access.log" | awk '{print $1}'
3) Обнулим файл
Выполним команду и чтобы очистить место на диске которое до сих пор занимает удаленный файл
truncate -s 0 /proc/4403/fd/29
Место освобождено
Чтобы не выполнять эти действия вручную, можно воспользоваться интерактивным скриптом в виде функции, который сделает все за Вас
clean-deleted-space() { DELETED_FILES=$(cat << EOL $(lsof 2>/dev/null | grep -s deleted | grep -Po "\w+\s+\w+\s+/.*" | awk '{print $1" "$3}' | sort -u | grep -v '^0') EOL ) cat << EOL | awk '{sum+=$1} END {print "Will released: "sum/1024/1024" Mb"}' ${DELETED_FILES} EOL ONLY_FILES=$(cat << EOL | awk '{print $2}' | grep '^/' ${DELETED_FILES} EOL ) cat << EOL ${ONLY_FILES} EOL echo "Are you sure to release space of deleted files above?" echo select CLEAN in Yes No do if [ "$CLEAN" = "Yes" ] then for DFILE in ${ONLY_FILES} do echo echo File: $DFILE FILE_DESC_ADDR=$(find /proc/*/fd -ls 2> /dev/null | grep '(deleted)' | sed 's#\ (deleted)##g' | awk '{print $11" "$13}' | sort -u -k 2 | grep $DFILE | awk '{print $1}') if [ "$FILE_DESC_ADDR" != "" ] ; then echo "executing: truncate -s 0 ${FILE_DESC_ADDR}" truncate -s 0 ${FILE_DESC_ADDR} echo done else echo "Truncate deleted file $DFILE is impossible, skip" fi echo done else echo Nothing to do fi break done } clean-deleted-space
Пример использования скрипта:
root@cloudmaker ~ $ clean-deleted-space Will released: 7.37246 Mb /var/log/zabbix/zabbix_agentd.log-20180916 /var/log/salt/minion-20180923 Are you sure to release space of deleted files above? 1) Yes 2) No ? 1 File: /var/log/zabbix/zabbix_agentd.log-20180916 executing: truncate -s 0 /proc/4186/fd/1 done File: /var/log/salt/minion-20180923 executing: truncate -s 0 /proc/4213/fd/6 done
0 Comments