Find: Difference between revisions

From Leo's Notes
This page was last edited on 3 December 2021, at 20:45.
 
(33 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 . '''-name''' <term>
{{highlight|lang=terminal|code=
# find . -name <term>    # name - case sensitive
# find . -iname <term>   # iname - case insensitive name
}}


You may want to use '''<code>-iname</code>''' for case insensitivity.
The term you pass in must match the entire file name. You can use * as a wild card.
 
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':
{{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
}}


== Find by time ==
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:
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.


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:
{{highlight|lang=terminal|code=
# find . -cmin -1
}}
 
===By Ownership (groups or user)===
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
}}


To find a file accessed within 1 day ago:
==Operators==
find . -amin -1


== Do things on match ==
You can mix and match the expressions discussed above with operators.
 
{| class="wikitable"
!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 <code>\( \)</code>.
|-
|!
|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:
Basic usage:
  find . '''-exec'''
{{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).


find . -iname "*.java" -exec sh -c 'iconv -f cp1252 -t utf-8 {} > {}.utf8' \;
{{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