Monday, November 16, 2009

Truncating a file

There are situations when you want to adjust the size of a file rather than deleting it. Especially when the file is being used by a process and you want to reduce its size without interrupting the process. Removing a file and creating another file by the same name will not work in such cases as the inode number of the file will change. This happens mainly with log files, where you want to reduce the size of the log - to save space -but don't want to stop the process that is writing to the log.

BSD has an excellent tool for this - the "truncate" command. This command can be used either to reduce/increase the size of a file. Let us consider a live example.

safeer->vps1.safeer.in ~ $ du -hs mysql-slowquery.log
476M mysql-slowquery.log

To reduce the size to 300MB

safeer->vps1.safeer.in ~ $ truncate -s 300M mysql-slowquery.log
safeer->vps1.safeer.in ~ $ du -hs mysql-slowquery.log
300M mysql-slowquery.log

Instead of specifying the exact size, if you just want to free up a 100Mb of disk space, you can do it this way:

safeer->vps1.safeer.in ~ $ truncate -s -100M mysql-slowquery.log
safeer->vps1.safeer.in ~ $ du -hs mysql-slowquery.log
200M mysql-slowquery.log

When you truncate a file by this method, the data is lost from the end of the file.

Truncate also has an option to extend a file's size, but it do not allocate any space for that. So it is not so useful.

safeer->vps1.safeer.in ~ $ truncate -s +400M mysql-slowquery.log
safeer->vps1.safeer.in ~ $ du -hs mysql-slowquery.log
200M mysql-slowquery.log

Another way of specifying size for truncation is to give a reference file. Truncate will calculate the size of the referenced file and truncate the given file to its length.

safeer->vps1.safeer.in ~ $ du -hs httpd.log mysql-slowquery.log
153M httpd.log
200M mysql-slowquery.log
safeer->vps1.safeer.in ~ $ truncate -r httpd.log mysql-slowquery.log
safeer->vps1.safeer.in ~ $ du -hs httpd.log mysql-slowquery.log
153M httpd.log
153M mysql-slowquery.log

truncate do not change the inode of the file.

safeer->vps1.safeer.in ~ $ ls -i mysql-slowquery.log
48980316 mysql-slowquery.log
safeer->vps1.safeer.in ~ $ truncate -s -132M mysql-slowquery.log
safeer->vps1.safeer.in ~ $ ls -i mysql-slowquery.log
48980316 mysql-slowquery.log

As you can see, this is a very useful command, but unfortunately we don't have a similar tool in Linux. So we can use any of the following method to emulate some truncate features.

To empty a file (truncate -s 0 )

safeer@penguinpower:~$ du -hs mysql-slowquery.log
1.1G mysql-slowquery.log
safeer@penguinpower:~$ >mysql-slowquery.log
safeer@penguinpower:~$ du -hs mysql-slowquery.log
0 mysql-slowquery.log

For resizing to an exact size you can use the dd command.

safeer@penguinpower:~$ du -hs mysql-slowquery.log
747M mysql-slowquery.log
safeer@penguinpower:~$ dd if=/dev/null seek=705 bs=1M of=mysql-slowquery.log
0+0 records in
0+0 records out
0 bytes (0 B) copied, 5.1892e-05 s, 0.0 kB/s
safeer@penguinpower:~$ du -hs mysql-slowquery.log
706M mysql-slowquery.log

Here dd argument bs specifies the unit of file size where as seek will specify the number of units to which you want to resize the file. Technically, copying /dev/null to a file will erase the content in the destination file. But with the "seek" option we specify that "seek value" X "block size" data from the beginning of the file should be preserved and the rest of the data should be erased. So in the above example, file was reduced to ~705MB (705 * 1M).

The following commands are equivalent.

truncate -s 0 mysql-slowquery.log
>mysql-slowquery.log
cat /dev/null > mysql-slowquery.log
dd if=/dev/null of=mysql-slowquery.log

No comments:

Post a Comment