How to clean up disk space if after deleting a file disk space is not released - interactive bash script
1) You can view the list of all deleted files with open file descriptors using the command
lsof | grep deleted
In the output, we get strings type of
nginx 4403 4430 nginx 29w REG 8,1 5779197 165960 /tmp/access.log (deleted)
The eighth column in the eighth column we can see the file size in bytes, but we are interested in the location of the file descriptor, so that the first part of the path to it is the second output column, in this case 4403
2) Find the full path to the handle
Run the command below by substituting 4403 after /proc/ and the file name in the grep pattern
ls -l /proc/4403/fd | grep "/tmp/access.log"
The output from the command should look something like this:
l-wx------ 1 nginx nginx 64 Oct 30 15:21 29 -> /tmp/access.log (deleted)
Here we see the second part of the path, this is the 9th column, number 29
As a result, the full path to the file descriptor of the remote file looks like this:
/proc/4403/fd/29
Also, the path to the file for cleaning can be obtained using the following command (several awk iterations are used for additional validation)
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 the file
Run the command and to clear the disk space that still takes up the deleted file
truncate -s 0 /proc/4403/fd/29
Disk space released
In order not to perform these actions manually, you can use the interactive script as a function that will do everything for you
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
Example script usage:
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