A blog post about finding stale pyc files got some of my interests, especially the conjunctive use of -exec and -print:

find . -name '*.pyc' \
       -exec bash -c 'test "$1" -ot "${1%c}"' -- {} \; \
       -print  #stalepyc

Truth to be told and from all cases I have seen, -exec was always the last one in find command, so this blog post just broadened my narrow view of the command.

Nevertheless, the Bash blood in my vein had whispered in my ear as soon as I saw it, there is going to be a performance issue because every found pyc file costs one Bash execution. Thats costly.

You can simply pipe the output to a while loop, although this isnt not the purpose of writing this post, but here it is:

find . -name '*.pyc' |
while read f; do test "$f" -ot "${f%c}"; echo "$f"; done

It was more than ten times faster on my computer, 0.100s down to just 0.008s. Note that I keep test builtin, but usually Id prefer [[ ]] keyword.

Anyway, I have never had an issue with pyc files, they always get re-compiled correctly once the source is updated. So, not really sure where the issue actually comes from under what kind of situation. I guess I am not really an advanced Python coder after all.

But the comments in the blog post brought up another case, or part of, there are no sources. Not an issue, just worth finding those pyc files. Initially, I came up with

find . -name '*.pyc' \
  \( \
    -exec sh -c 'test ! -f "${1%c}"' -- {} \; \
    -printf 'source not found: ' \
    -print \
  \) \
  -o \
  \( \
    -exec sh -c 'test "$1" -ot "${1%c}"' -- {} \; \
    -print \
  \)

This is my first time that I have used -o (or operator) and stacked printing actions, never thought of such way to use find until now. Note that I use -f not -e, for some strange reason that only god knows, I suspect weird situation like weird.py directory would show up alongside weird.pyc file. Also note that sh is used instead of bash, there seems to be no need for using bash. Ive checked POSIX standard the ${parameter%[word]} expansion is defined, compatibility wouldnt be a problem.

How about pyd, pyo, or pyWhatever?

find -name '*.py?*' \
     -exec sh -c 'test ! -f "${1%.py*}.py"' -- {} \; \
     -printf 'source not found: ' \
     -print

The *.py?* pattern matches at least one character after py, .py* in the end of the matched filename is stripped and put back only .py, so that formed source filename can be checked by test. This can be easily adapted to delete all those pyWhatever files by using -delete action, if that fits your needs.

There is always more to learn about everything you think you have known.