GNU find

find – search for files in a directory hierarchy

General

Global Options

-maxdepth levelsDescend at most levels (a non-negative integer) levels of directories below the starting-points
-mount
-xdev
Don’t descend directories on other filesystems

Tests

-name patternBase of file name (the path with the leading directories removed) matches shell pattern pattern
-user unameFile is owned by user uname (numeric user ID allowed)

Tasks

Delete files matching several patterns (OR)

Test it before adding the -delete !

find ~/Music \( -name '*.pls' -o -name '*.m3u' -o -name '*.md5' -o -name '*.nfo' \)
find ~/Music \( -name '*.pls' -o -name '*.m3u' -o -name '*.md5' -o -name '*.nfo' \) -delete

Delete files NOT matching several patterns (AND)

find ~/Music -type f ! \( \
-name '*.mp3' \
-o -name '*.flac' \
-o -name '*.m4a' \
-o -name '*.jpg' \
-o -name '*.jpeg' \
-o -name '*.wav' \
-o -name '*.ogg' \
-o -name '*.png' \
-o -name '*.mp4' \
-o -name '*.au' \
-o -name '*.mp2' \
-o -name '*.opus' \
\)

Move all matching files to a special directory

find . -name "pattern*" -type f -print0 | xargs -r0 /bin/mv -t /path/to/directory/

Find files NOT matching a pattern

find . ! -name "*20.04*"
find . ! -name "*20.04*" -delete

Find files with forbidden characters in SMB

find /projects/ -regex '.*[\:*?"<>|]+.*'

Find files with a trailing whitespace

find /projects/ -regex '.* $'

Delete empty directories

find . -type d -empty -delete

List directory, outputs only the last part and sort it

find /my/path -mindepth 1 -maxdepth 1 -type d -printf "%f\n" | sort -n

Clean and rename files

find . -regex '.* $' -or -regex '.*[\:*?"<>|]+.*' -exec /home/leo/filename_cleaner '{}' \;

with filename_cleaner:

#!/bin/sh

echo "old filename: $1"
oldfilename=$1
newfilename=`echo $1 | sed 's/\(.*\) $/\1/' | sed 's/[\:*?"<>|]//g'`
echo "new filename: $newfilename"
mv -vi "$1" "$newfilename"

Remove old files

Remove recursively all files that are older than 3 months

From the find man page:

  • -type f regular file
  • -mtime n File’s data was last modified n*24 hours ago
  • -delete Delete files; true if removal succeeded.
find /var/log/ -type f -mtime +90 -delete -print

Set permissions differently on folders and files (several filter/action)

We want to set the permissions of:

  • directories to 770 which is rwx for user (owner) and group (execute for folders allows to list contents)
  • files to 660 which is rw for user and group
find mydir \( -type d -exec chmod 770 '{}' \; \) , \( -type f -exec chmod 660 '{}' \; \)

This is achieved in one pass.

Expressions

using :

leo@computer:~$ find test/
test/
test/file01.txt
test/file02.jpg
test/file03.zip

Or:

leo@computer:~$ find test/ -name *.zip -or -name *.jpg
test/file02.jpg
test/file03.zip

Not:

leo@computer:~$ find test/ -not -name *.zip
test/
test/file01.txt
test/file02.jpg