6

I've got a program that's behaving badly and has created a number of files with only a few non-printing characters. If I were to cat the files, I see nothing (since they are non-printing chars). However, these files will not show up if I use something like -empty or -size 0 with the find command.

Does anyone know of a way to search for files containing only non-printing characters?

9

With GNU grep (and several other grep implementations), you can search for files that do not contain any printable character. The -L option means to list the files that do not contain a match. [[:print:]] (yes, there are two pairs of brackets) matches one printable character; the definition of printable character depends on your locale.

grep -L '[[:print:]]' -- *

Note that this includes empty files (as mindas pointed out).

To delete them all (review the grep output first to make sure you're deleting the right files), assuming that the file names don't contain any newline character:

grep -L '[[:print:]]' -- * |
while IFS= read -r filename; do
  if [ -f "$filename" ] && [ -s "$filename" ]; then
    rm "$filename"
  fi
done

or equivalently (note that this deletes empty files as well)

set +f; IFS='
' # split at newlines, turn off globbing
rm -- $(set -f; grep -L '[[:print:]]' -- *)
set -f; unset IFS

Note that the commands above will produce error messages if there are subdirectories in the current directory (because you'll be calling rm on a directory — don't call rm -r!). In zsh, you can use *(.L+0) instead of * to only match regular non-empty files, and you don't need to worry about special characters in file names (except newlines):

IFS=$'\n'
rm -- $(grep -L '[[:print:]]' -- *(.))
unset IFS

With only POSIX tools, grep -l '[[:print:]]' -- * shows the files you want to keep (except empty files).

Or you can iterate over the files; this is clearer, and sure not to cause any trouble with special chacters (but skips dot files), but theoretically (but probably not measurably) slower.

for x in *; do
  if [ -f "$x" ] && [ -s "$x" ] && ! grep -q '[[:print:]]' <"$x"; then
    rm -- "$x"
  fi
done
  • 1
    Note: grep -L '[[:print:]]' -- * also lists empty files (having size of 0 bytes) -- this might or might not be desirable. Technically they don't contain NPSs. – mindas Jun 18 '13 at 14:16
4

Your best bet is probably to use file. Try this:

find . -type f -exec file {} + | grep ": data"

Now, this won't catch files that randomly happen to have the right magic number at the start, but it's quite likely most other methods would miss them anyway.

Other ways to find these files:

  • Last modified time: find -mmin 5 = 5 mins ago
  • Size, not necessarily zero: find -size -4k = less than 4096 Bytes

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.