Find: Difference between revisions

From Leo's Notes
This page was last edited on 3 December 2021, at 20:45.
 
(27 intermediate revisions by the same user not shown)
Line 1: Line 1:
<code>find</code> is one of those commands that can be quite arcane. Hopefully this article should clear things up with a brief list of basic uses.  
{{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.  


One of the nice things with <code>find</code> is that you can chain multiple things together.
==Find Expressions==


== Find a specific type ==
===By File Type===
Basic usage:
Basic usage:
find . '''-type''' [f - file|d - directory|l - links]
{{highlight|lang=terminal|code=
# find . -type [f - file{{!}}d - directory{{!}}l - links]
}}


To find only normal files:
To find only normal files:
find . -type f
{{highlight|lang=terminal|code=
# find . -type f
}}


To find both files and directories:
To find both files and directories:
find . -type f -o -type d
{{highlight|lang=terminal|code=
# find . -type f -o -type d
}}


== Find by filename ==
===By filename===
Basic usage:
Basic usage:
  find . -['''i''' - case insensitive]name <term>
{{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 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.
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':
find . -name confession.txt -type f
{{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':
find . -iname backup -type d
{{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:
find . -regextype posix-egrep -regex ".?\/?[0-9]{3}-[0-9]{4}.txt"
{{highlight|lang=terminal|code=
# find . -regextype posix-egrep -regex ".?\/?[0-9]{3}-[0-9]{4}.txt"
}}


== Find by time ==
===By time (created, access, modified)===
Basic usage:
Basic usage:
find . -['''a''' - accessed|'''c''' - created|'''m''' - modified]['''time'''|'''min'''] <time>
{{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:
find . -mmin -3
{{highlight|lang=terminal|code=
# find . -mmin -3
}}


To find files created within 1 day ago:
To find files created within 1 day ago:
find . -cmin -1
{{highlight|lang=terminal|code=
# find . -cmin -1
}}


== Do things on match ==
===By Ownership (groups or user)===
Basic usage:
Basic usage:
find . '''-exec''' <command> {} \;
{{highlight|lang=terminal|code=
# find . -[user{{!}}group] <name or id>
}}


The {} is substituted with the matching filename.
#find is able to find file owners by their username or user ID or by group name or group ID.
The \; at the end denotes the end of the command passed to -exec.


To move all .o files to /tmp/objects:
To find all files owned by leo:
find . -iname "*.o" -exec mv {} /tmp/{} \;
{{highlight|lang=terminal|code=
<code>/tmp/{}</code> can be simplified to </code>/tmp</code>, but this shows you can use {} more than once.
# find . -user leo
}}


To convert all .php files into UTF-8 files
==Operators==
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
 
== 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"
! Operator
!Operator
! Description
!Description
! Example
!Example
! Notes
!Notes
|-
|-
| ( )
|( )
| Force precedence  
|Force precedence
| ( -type f -o type d ) -o -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: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>
  1. 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