0

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
4

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
  • "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. – Toby Speight Aug 19 '15 at 8:24
  • 1
    Depends if file opened with O_APPEND or not. If not, then truncating file does not affect seek pointers. – user3188445 Aug 19 '15 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. – user3188445 Aug 19 '15 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. – Toby Speight Aug 19 '15 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 Sep 4 '17 at 2:58
2

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
    This is more complicated than necessary. Note that the shell built-in : or the true command is better than cat /dev/null. – user3188445 Aug 18 '15 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 Aug 18 '15 at 9:22
  • Also, if you are using IFS anyway why not truncate --size 0 $(find . -type f -size +2097152c)? – user3188445 Aug 18 '15 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 ...
  • It returns the error "find: missing argument to `-exec'" – Leslin Jea Aug 18 '15 at 8:05
  • @LeslinJea: What command did you run exactly? Do you copy paste or typing by your self? – cuonglm Aug 18 '15 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.

  • 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. – Gilles Aug 18 '15 at 22:10
  • Its working well for me, it makes the file size to zero byte @Gilles – Leslin Jea Aug 21 '15 at 2:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.