How to Clean Up Disk Space with Interactive Bash Script
Each of us may have come across situations when deleting unnecessary files on a server (on Linux machines based on CentOS, Debian, Ubuntu) did not clean up the disk space.
In this article, we’ll explain how to run a Bash script and clean up disk space on Ubuntu, Debian, or CentOS if deleting files hasn’t helped to free up your disk space.
1) You can view the list of all deleted files with open file descriptors using this command:
lsof | grep deleted
In the output, we get the strings:
nginx 4403 4430 nginx 29w REG 8,1 5779197 165960 /tmp/access.log (deleted)
In the eighth column we can see the file size in bytes. However, we need to know the location of the file descriptor. The first part of the path to the file descriptor is the second output column, which is in our case4403.
2) Find the full path to the handle.
Run the command below by inserting 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 like this:
l-wx------ 1 nginx nginx 64 Oct 30 15:21 29 -> /tmp/access.log (deleted)
Here we can see the second part of the path — the 9th column, number 29.
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 to clear the disk space that is still taken up by the deleted file:
truncate -s 0 /proc/4403/fd/29
Disk space has been freed up.
In order not to perform these actions manually, you can use the interactive bash script as a function:
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
Here’s an example of the 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