2

Considering if I list files in a directory:

drwx--x--x 43 root wheel 4.0K Aug 18 12:52 ..
-rw-------  1 root root  268K Aug 18 04:31 build_locale_databases_log
-rw-------  1 root root  5.2M Aug 18 17:21 access_log
-rw-------  1 root root   85K Aug 18 17:14 cpbackup_transporter.log
-rw-------  1 root root  2.1M Aug 18 05:49 cphulkd.log
-rw-------  1 root root  3.2M Aug 18 17:19 error_log
-rw-------  1 root root  1.7M Aug 18 12:52 license_log

Here I want to clear the contents of the files which are greater than 2Mb. (i.e) to make the file size to zero bytes for the following files:

access_log
cphulkd.log
error_log

5 Answers 5

5

I like to answer the direct question first, but do not run this before reading to the end of my answer. The command you are asking for (which may not be what you want) is:

find /wherever -type f -name '*.log' -size +4096 -print \
    | xargs truncate --size 0

Note that the +4096 means files with more than 4096 512-byte sectors. The problem is that if these are log files that a process is actively writing to, those processes will keep their position in the file. You'll recover the disk space (assuming your file system supports sparse files, which most do), but when you go to look at your logs there will be blocks of zeros at the beginning. So you really need to restart your daemon right after doing this, or better yet move the files out of the way and restart your daemons:

cd /wherever
find . -name '*.log' -maxdepth 1 -size +4096 -exec mv {} {}.old \;
systemctl restart yourservice (or whatever you need to restart)
rm -f *.old
5
  • "those processes will keep their position in the file" - are you sure? I've just tested, using exec 3>>foo; echo test test >&3; cat foo; : >foo; echo bam bam >&3; cat foo, and the same with > instead of >>; in both cases the write position was correctly reset to the new end of file. Commented Aug 19, 2015 at 8:24
  • 1
    Depends if file opened with O_APPEND or not. If not, then truncating file does not affect seek pointers. Commented Aug 19, 2015 at 8:27
  • On linux 4.1.5, if I run yes > mylogfile & sleep 1; :>mylogfile; kill %yes and look at mylogfile with hexdump, there are tons of 0-valued bytes at the beginning of the file. Commented Aug 19, 2015 at 13:38
  • Ah, you're right (and I can repro that with my earlier approach if I write more than a single block - e.g. exec 3>mylogfile; timeout 0.1 yes >&3; ls -log mylogfile; :>mylogfile; ls -log mylogfile; echo >&3; ls -log mylogfile). And exec 3>>mylogfile behaves. Commented Aug 19, 2015 at 13:58
  • find /data -type f -size +5G -exec truncate -s0 {} \; in general. Specifically to the OP question: find /data -type f -name '*log' -size +2M -exec truncate -s0 {} \;.
    – ILMostro_7
    Commented Sep 4, 2017 at 2:58
3

You can do this by a find command:

for i in $(find . -type f -size +2097152c);do  cat /dev/null > $i;done

The find command find . -type f -size +2097152c will find all files of size greater than

2MB (2097152 bytes)

The for loop will loop into the list of the files it got in the find command and will clean them out with a cat /dev/null

------Edit------

As suggested by user3188445 You can try this way also

for i in $(find . -type f -size +2097152c);do  :  > $i;done
3
  • 3
    This is more complicated than necessary. Note that the shell built-in : or the true command is better than cat /dev/null. Commented Aug 18, 2015 at 8:15
  • 1
    Note that this won't work with file contain newline, and will empty all files in current directory if filename contain ` * `.
    – cuonglm
    Commented Aug 18, 2015 at 9:22
  • Also, if you are using IFS anyway why not truncate --size 0 $(find . -type f -size +2097152c)? Commented Aug 18, 2015 at 13:09
0

Posixly:

find . ! -name . -prune -type f -size +2097152c -exec sh -c '
  for f do
    : > "$f"
  done
' sh {} +

With GNU find or BSD find:

find . -maxdepth 1 -type f -size +2M ...
2
  • It returns the error "find: missing argument to `-exec'"
    – Leslin Jea
    Commented Aug 18, 2015 at 8:05
  • @LeslinJea: What command did you run exactly? Do you copy paste or typing by your self?
    – cuonglm
    Commented Aug 18, 2015 at 9:21
0
while read -r line; do
    truncate -s 0 $line
done < <(find / -type f -name '*.log' -size +2M)
-2

I came up with:

find . -type f -size '+2M' -print | while read i
do
echo " " > $i
done

which works.

2
  • which doesn't work. It writes two bytes in the file. Use : >"$i" to truncate the file to 0 bytes. Using -print | while read only works for file names that don't contain special characters, you should use find -exec … or find … -print0 | xargs -0 instead. Commented Aug 18, 2015 at 22:10
  • Its working well for me, it makes the file size to zero byte @Gilles
    – Leslin Jea
    Commented Aug 21, 2015 at 2:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .