Find: Difference between revisions
mNo edit summary |
|||
| (21 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
{{code|find}} is one of those commands that can be quite arcane. Hopefully this article should clear things up with a brief list of basic uses. | |||
== Find | ==Find Expressions== | ||
===By File Type=== | |||
Basic usage: | Basic usage: | ||
{{highlight|lang=terminal|code= | |||
# find . -type [f - file{{!}}d - directory{{!}}l - links] | |||
}} | |||
To find only normal files: | To find only normal files: | ||
{{highlight|lang=terminal|code= | |||
# find . -type f | |||
}} | |||
To find both files and directories: | To find both files and directories: | ||
{{highlight|lang=terminal|code= | |||
# find . -type f -o -type d | |||
}} | |||
== | ===By filename=== | ||
Basic usage: | Basic usage: | ||
find . - | {{highlight|lang=terminal|code= | ||
# find . -name <term> # name - case sensitive | |||
# find . -iname <term> # iname - case insensitive name | |||
}} | |||
The term you pass in must match the entire file name. You can use * as a wild card. | |||
The | For regex matching, use {{code|-regex}}. The default regex used by find is emacs-regex. To define something else (like posix), use {{code|-regextype}}. | ||
====Examples==== | |||
To find a file named exactly 'confession.txt': | To find a file named exactly 'confession.txt': | ||
{{highlight|lang=terminal|code= | |||
# find . -name confession.txt -type f | |||
}} | |||
To find a directory named 'backup' or 'Backup': | To find a directory named 'backup' or 'Backup': | ||
{{highlight|lang=terminal|code= | |||
# find . -iname backup -type d | |||
}} | |||
To find a file with the format NNN-NNNN.txt where N is an integer: | To find a file with the format NNN-NNNN.txt where N is an integer: | ||
{{highlight|lang=terminal|code= | |||
# find . -regextype posix-egrep -regex ".?\/?[0-9]{3}-[0-9]{4}.txt" | |||
}} | |||
== | ===By time (created, access, modified)=== | ||
Basic usage: | Basic usage: | ||
{{highlight|lang=terminal|code= | |||
# find . -[a - accessed{{!}}c - created{{!}}m - modified][time{{!}}min] <time> | |||
}} | |||
where time is in days when used with time, or minutes when used with min. | where time is in days when used with time, or minutes when used with min. | ||
To find files modified within 3 minutes ago: | To find files modified within 3 minutes ago: | ||
{{highlight|lang=terminal|code= | |||
# find . -mmin -3 | |||
}} | |||
To find files created within 1 day ago: | To find files created within 1 day ago: | ||
{{highlight|lang=terminal|code= | |||
# find . -cmin -1 | |||
}} | |||
== | ===By Ownership (groups or user)=== | ||
Basic usage: | Basic usage: | ||
{{highlight|lang=terminal|code= | |||
# find . -[user{{!}}group] <name or id> | |||
}} | |||
#find is able to find file owners by their username or user ID or by group name or group ID. | |||
To find all files owned by leo: | |||
{{highlight|lang=terminal|code= | |||
# find . -user leo | |||
}} | |||
==Operators== | |||
== Operators == | |||
You can mix and match the expressions discussed above with operators. | You can mix and match the expressions discussed above with operators. | ||
{| class="wikitable" | {| class="wikitable" | ||
! Operator | !Operator | ||
! Description | !Description | ||
! Example | !Example | ||
! Notes | !Notes | ||
|- | |- | ||
| ( ) | |( ) | ||
| Force precedence | |Force precedence | ||
| ( -type f -o type d ) -a -name "exception.txt" | |( -type f -o type d ) -a -name "exception.txt" | ||
| | |Both brackets must be surrounded by at least one space. When scripting, you may need to escape the brackets as <code>\( \)</code>. | ||
|- | |- | ||
| ! | |! | ||
| not | |not | ||
| ! -name "exception.txt" | |! -name "exception.txt" | ||
| Can also use -not | |Can also use -not | ||
|- | |- | ||
| -a | | -a | ||
| And | |And | ||
| -type f -a -name "confession.txt" | | -type f -a -name "confession.txt" | ||
| This is the default operator. Can also use -and | |This is the default operator and can be omitted. Can also use -and | ||
|- | |- | ||
| -o | | -o | ||
| Or | |Or | ||
| -name "confession.txt" -o -name "murder.txt" | | -name "confession.txt" -o -name "murder.txt" | ||
| Can also use -or | |Can also use -or | ||
|} | |} | ||
==Do things on match== | |||
Basic usage: | |||
{{highlight|lang=terminal|code= | |||
# find . -exec <command> {} \; | |||
}} | |||
The {{code|{}|}} is substituted with the matching filename. | |||
The {{code|\;}} at the end denotes the end of the command passed to {{code|-exec}}. | |||
===Move all .o files to /tmp/objects=== | |||
{{highlight|lang=terminal|code= | |||
# find . -iname "*.o" -exec mv {} /tmp/{} \; | |||
}} | |||
The move command could be simplified so that the destination location is just a directory name (ie: {{code|-exec mv {} /tmp}}). The example above was done to show that you can use {{code|{}|}} can be used more than once. | |||
===Convert all .php files into UTF-8 files=== | |||
The following are two separate commands. Run them sequentially. | |||
{{highlight|lang=terminal|code= | |||
# find . -iname "*.php" -exec sh -c 'iconv -f cp1252 -t utf-8 {} > {}.utf8' \; | |||
# for i in `(find . -name "*.utf8")`; do mv $i ${i/.utf8/}; done | |||
}} | |||
===Change the file mode for files to 644 and directories to 755=== | |||
{{highlight|lang=terminal|code= | |||
# find . -type f -exec chmod -v 644 {} \; | |||
# find . -type d -exec chmod -v 755 {} \; | |||
}} | |||
====Finding bad permissions==== | |||
You may also find files and directories without the permissions like so: | |||
{{highlight|lang=terminal|code= | |||
# find ! -perm 644 -type f -o ! -perm 755 -type d | |||
}} | |||
===Remove all broken symlinks=== | |||
{{highlight|lang=terminal|code= | |||
# find . -type l -! -exec test -e {} \; -print {{!}} while read i ; do rm -v $i ; done | |||
}} | |||
===Grepping for lines on match=== | |||
Suppose you want to find all <code>.htaccess</code> files and check if they have an <code>AuthType</code> directive. | |||
{{highlight|lang=terminal|code= | |||
# find . -name .htaccess -exec grep -oHne 'AuthType.*$' {} \; | |||
}} | |||
===Update file ownership after renumbering an account=== | |||
After updating an account's uid, you may wish to update all files that were owned with the old uid. Do so in a parallelized fashion by running: | |||
{{Highlight | |||
| code = # cd /data/shared_dir | |||
# ls {{!}} xargs -L 1 -P 6 -I '<nowiki>{{' find {{</nowiki> -user $OLDUID -exec chown $NEWUID:$NEWGID "{}" \; | |||
| lang = terminal | |||
}} | |||
===Parallelizing Jobs=== | |||
To run multiple jobs across all files found by {{code|find}}, use {{code|xargs}}. | |||
Suppose you wanted to resize all pictures inside a directory using a resize script. To run this across all 8 CPUs: | |||
{{highlight|lang=terminal|code= | |||
# find . -iname '*.jpg' -print0 {{!}} xargs -0 -P 8 sh resize.sh | |||
}} | |||
Note that we print the file using {{code|-print0}} which delimits filenames with a null rather than newlines. {{code|xargs}} can then delimit using a null with the {{code|-0}} flag. | |||
For completeness's sake, here is the resize.sh script: | |||
{{highlight|lang=bash|code= | |||
#!/bin/sh | |||
for i in "$@" ; do | |||
File=`identify -format '%w %h %i\n' "$i" \ | |||
{{!}} awk '$1 > 1920 {{!}}{{!}} $2 > 1920 {sub(/^[^ ]* [^ ]* /, ""); print}' ` | |||
if [ ! -z "$File" ] ; then | |||
echo "Resizing $File" | |||
mogrify -resize "1920x1920" "$File" | |||
fi | |||
done | |||
}} | |||
===Removing old files=== | |||
Remove all files older than 100 days (such as to clear a <code>/tmp</code> directory). | |||
{{highlight|lang=terminal|code= | |||
$ find . -type f -mtime +100 -exec rm -v {} \; | |||
}} | |||
=== Removing empty files and directories === | |||
{{Highlight | |||
| code = $ find . -type d -empty -delete | |||
| lang = terminal | |||
}}<br />{{Navbox Linux}} | |||
[[Category:Linux]] | |||
[[Category:FreeBSD]] | [[Category:FreeBSD]] | ||
[[Category:TipsnTricks]] | [[Category:TipsnTricks]] | ||
[[Category:LinuxUtilities]] | |||
Latest revision as of 20:45, 3 December 2021
find is one of those commands that can be quite arcane. Hopefully this article should clear things up with a brief list of basic uses.
Find Expressions
By File Type
Basic usage:
# find . -type [f - file|d - directory|l - links]
To find only normal files:
# find . -type f
To find both files and directories:
# find . -type f -o -type d
By filename
Basic usage:
# find . -name <term> # name - case sensitive
# find . -iname <term> # iname - case insensitive name
The term you pass in must match the entire file name. You can use * as a wild card.
For regex matching, use -regex. The default regex used by find is emacs-regex. To define something else (like posix), use -regextype.
Examples
To find a file named exactly 'confession.txt':
# find . -name confession.txt -type f
To find a directory named 'backup' or 'Backup':
# find . -iname backup -type d
To find a file with the format NNN-NNNN.txt where N is an integer:
# find . -regextype posix-egrep -regex ".?\/?[0-9]{3}-[0-9]{4}.txt"
By time (created, access, modified)
Basic usage:
# find . -[a - accessed|c - created|m - modified][time|min] <time>
where time is in days when used with time, or minutes when used with min.
To find files modified within 3 minutes ago:
# find . -mmin -3
To find files created within 1 day ago:
# find . -cmin -1
By Ownership (groups or user)
Basic usage:
# find . -[user|group] <name or id>
- find is able to find file owners by their username or user ID or by group name or group ID.
To find all files owned by leo:
# find . -user leo
Operators
You can mix and match the expressions discussed above with operators.
| Operator | Description | Example | Notes |
|---|---|---|---|
| ( ) | Force precedence | ( -type f -o type d ) -a -name "exception.txt" | Both brackets must be surrounded by at least one space. When scripting, you may need to escape the brackets as \( \).
|
| ! | not | ! -name "exception.txt" | Can also use -not |
| -a | And | -type f -a -name "confession.txt" | This is the default operator and can be omitted. Can also use -and |
| -o | Or | -name "confession.txt" -o -name "murder.txt" | Can also use -or |
Do things on match
Basic usage:
# find . -exec <command> {} \;
The {} is substituted with the matching filename.
The \; at the end denotes the end of the command passed to -exec.
Move all .o files to /tmp/objects
# find . -iname "*.o" -exec mv {} /tmp/{} \;
The move command could be simplified so that the destination location is just a directory name (ie: -exec mv {} /tmp). The example above was done to show that you can use {} can be used more than once.
Convert all .php files into UTF-8 files
The following are two separate commands. Run them sequentially.
# find . -iname "*.php" -exec sh -c 'iconv -f cp1252 -t utf-8 {} > {}.utf8' \;
# for i in `(find . -name "*.utf8")`; do mv $i ${i/.utf8/}; done
Change the file mode for files to 644 and directories to 755
# find . -type f -exec chmod -v 644 {} \;
# find . -type d -exec chmod -v 755 {} \;
Finding bad permissions
You may also find files and directories without the permissions like so:
# find ! -perm 644 -type f -o ! -perm 755 -type d
Remove all broken symlinks
# find . -type l -! -exec test -e {} \; -print | while read i ; do rm -v $i ; done
Grepping for lines on match
Suppose you want to find all .htaccess files and check if they have an AuthType directive.
# find . -name .htaccess -exec grep -oHne 'AuthType.*$' {} \;
Update file ownership after renumbering an account
After updating an account's uid, you may wish to update all files that were owned with the old uid. Do so in a parallelized fashion by running:
# cd /data/shared_dir
# ls | xargs -L 1 -P 6 -I '{{' find {{ -user $OLDUID -exec chown $NEWUID:$NEWGID "{}" \;
Parallelizing Jobs
To run multiple jobs across all files found by find, use xargs.
Suppose you wanted to resize all pictures inside a directory using a resize script. To run this across all 8 CPUs:
# find . -iname '*.jpg' -print0 | xargs -0 -P 8 sh resize.sh
Note that we print the file using -print0 which delimits filenames with a null rather than newlines. xargs can then delimit using a null with the -0 flag.
For completeness's sake, here is the resize.sh script:
#!/bin/sh
for i in "$@" ; do
File=`identify -format '%w %h %i\n' "$i" \
| awk '$1 > 1920 || $2 > 1920 {sub(/^[^ ]* [^ ]* /, ""); print}' `
if [ ! -z "$File" ] ; then
echo "Resizing $File"
mogrify -resize "1920x1920" "$File"
fi
done
Removing old files
Remove all files older than 100 days (such as to clear a /tmp directory).
$ find . -type f -mtime +100 -exec rm -v {} \;
Removing empty files and directories
$ find . -type d -empty -delete