diff --git a/knowledge base/find.md b/knowledge base/find.md index acb88f4..9c0d7a7 100644 --- a/knowledge base/find.md +++ b/knowledge base/find.md @@ -3,56 +3,140 @@ ## TL;DR ```shell -# change the permissions of all files and directories in the current directory, recursively +# Change the permissions of all files and directories in the current directory, +# recursively. find . -type d -exec chmod 755 {} + find . -type f -exec chmod 644 {} + -# change the ownership of all files and directories owned by a specific user or group, recursively +# Change the ownership of all files and directories owned by a specific user or +# group, recursively. find . -type d -user harry -exec chown daisy {} + find . -type f -group users -exec chown :admin {} + -# delete all empty files and directories in the 'Documents' directory +# Delete all empty files and directories in the 'Documents' directory. find Documents -empty -delete # recursively find Documents -maxdepth 1 -empty -delete # non recursively -# get the extensions of all files larger than 1MB +# Get the extensions of all files larger than 1MB. find . -type f -size +1M -exec basename {} \; | sed 's|.*\.||' | sort -u -# get all empty directories in a git repository (but not the repo's ones) -find $PATH_TO_REPO -type d -empty -not -path "./.git/*" +# Find files last accessed exactly 5 hour ago. +find . -type f -amin 300 +find . -type f -atime 5h -# find broken symlinks in the given directories, recursively -find $DIR1 $DIR2 $DIRN -type l -exec test ! -e {} ';' -print # posix -find $DIR1 $DIR2 $DIRN -xtype l # gnu find only +# Find files last modified in the last hour. +find . -type f -mmin -60 +find . -type f -mtime -1h -# get files by name, in numeric order regardless of the directory they are in +# Find files created more than 2 days ago. +find . -type f -ctime +2 + +# Find all empty directories in a git repository that are not from git itself. +find path/to/repo -type d -empty -not -path "./.git/*" + +# Find broken symlinks in the given directories, recursively. +find dir/1 dir/n -type l -exec test ! -e {} \; -print +find dir/1 dir/n -xtype l # gnu find only + +# Sort files by name, in numeric order, regardless of the directory they are in. find . -type f -o -type l \ | awk 'BEGIN {FS="/"; OFS="|"} {print $NF,$0}' \ | sort --field-separator '|' --numeric-sort \ | cut -d '|' -f2 -# print quoted file paths -# %p is for path +# Print quoted file paths. +# %p is for path. find . -type f -printf '%p\n' -# sort files by size -# %s is for size +# Sort files by size. +# %s is for size, %p is for path. find . -type f -printf '%s %p\n' | sort -nr | head -50 -# get files which are executable but not readable +# Find files which are executable but not readable. find /sbin /usr/sbin -executable -not -readable -print -# get files which are writable by either their owner or their group +# Find files which are writable by either their owner or their group. find . -perm /220 find . -perm /u+w,g+w find . -perm /u=w,g=w -# get files which are writable by both their owner and their group. +# Find files which are writable by both their owner and their group. find . -perm -220 find . -perm -g+w,u+w -# list set-user-ID files and directories into /root/suid.txt and list large files into /root/big.txt -find / \( -perm -4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \( -size +100M -fprintf /root/big.txt '%-10s %p\n' \) +# Record set-user-ID files and directories into '/root/suid.txt', and large +# files into 'big-files.txt' +find / \ + \( -perm -4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \ + \( -size +100M -fprintf big-files.txt '%-10s %p\n' \) +``` + +## Time specifications + +Primaries used to check the difference between the file last access, creation or modification time and the time `find` was started. + +All time specification primaries take a numeric argument, and allow the number to be preceded by a plus sign (`+`) or a minus sign (`-`). +A preceding plus sign means **more than `n`**, a preceding minus sign means **less than `n`** and neither means **exactly `n`**. + +Accepted time information: + +- `a` for the file's last access time +- `c` for the time of last change of file status information (creation) +- `m` for the file's last modification time +- `B` for the file's inode creation time + +With the `-Xmin` form, times are rounded up to the next full **minute**. This is the same as using `-Xtime Nm`. + +With the `-Xtime` form, times depend on the given unit; if no unit is given, it defaults to full 24 hours periods (days). +Accepted units: + +- `s` for seconds +- `m` for minutes (60 seconds) +- `h` for hours (60 minutes) +- `d` for days (24 hours) +- `w` for weeks (7 days) + +Any number of units may be combined in one `-Xtime` argument. + +with the `-newerXY file` form, `find` checks if `file` has a more recent last access time (X=a), inode creation time (X=B), change time (X=c), or modification time (X=m) than the last access time (Y=a), inode creation time (Y=B), change time (Y=c), or modification time (Y=m). +If Y=t, `file` is interpreted as a direct date specification of the form understood by `cvs`. Also, `-newermm` is the same as `-newer`. + +```shell +# Find files last accessed exactly 5 minutes ago. +find /dir -amin 5 +find /dir -atime 300s +find /dir -atime 5m + +# Find files last accessed in the last 3 days. +find /dir -atime -3 +find /dir -atime -3d + +# Find files created in the last 1.5 hour. +find /dir -cmin -90 +find /dir -ctime -1h30m + +# Find files created more than 4 days ago. +find /dir -ctime +4 + +# Find files modified less than 30 minutes ago. +find /dir -mmin -30 +find /dir -mtime -30m +find /dir -mtime -.5h # gnu find only + +# Find files modified exactly 2 days ago. +find /dir -mtime 2 +find /dir -mtime 48h + +# Find files modified more than 4 weeks ago. +find /dir -mtime +28 +find /dir -mtime +4w + +# Find all files whose inode change time is more recent than the current time +# minus one minute. +find / -newerct '1 minute ago' + +# Find files owned by 'wnj' that are newer than 'file.txt'. +find / -newer file.txt -user wnj -print ``` ## Gotchas @@ -60,10 +144,17 @@ find / \( -perm -4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \( -size +100M - in GNU's `find` the path parameter defaults to the current directory and can be avoided ```shell - # delete all empty folders in the current directory only + # Delete all empty folders in the current directory only. find -maxdepth 1 -empty -delete ``` +- GNU's `find` also understands fractional time specifications: + + ```shell + # Find files modified in the last 1 hour and 30 minutes. + find -mtime 1.5h + ``` + ## Further readings - [How can I find broken symlinks?]