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
Categories: CentosScripts

0 Comments

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *