Difference between revisions of "Find"
Line 110: | Line 110: | ||
find '...' -print0 | perl -0 -MURI::file -n -E 'chomp; say "".URI::file->new($_)' | find '...' -print0 | perl -0 -MURI::file -n -E 'chomp; say "".URI::file->new($_)' | ||
+ | |||
+ | ==Sorting by mtime== | ||
+ | |||
+ | find won't sort by mtime by itself. This general command produces a sorted result that should be acceptable by anything that would accept the result of `find … -print0`: | ||
+ | |||
+ | # Let $DESTZ be a command that accepts a list of null-terminated filenames | ||
+ | find … -printf '%T@ %p\0' | sort -zk 1n[r] | sed -z 's/^[^ ]* //' | $DESTZ | ||
+ | |||
+ | such as: | ||
+ | |||
+ | find -type f -printf '%T@ %p\0' | sort -zk 1n | sed -z 's/^[^ ]* //' | xargs -0 -i echo 'File: {}' | ||
+ | |||
+ | Breakdown: | ||
+ | |||
+ | # Note that the intermediate processing steps use \0-terminated lists in | ||
+ | # order not to lose information about oddly named files. | ||
+ | find … -printf '%T@ %p\0' | # Prefixes all files with their numeric mtime and a space | ||
+ | sort -zk 1n[r] | # Sorts lines numerically by the prefixes (use `1n` for old to new or `1nr` for new to old) | ||
+ | sed -z 's/^[^ ]* //' | # Strips the prefixes from the sorted result | ||
+ | $DESTZ # Accepts list of null-terminated filenames | ||
==Combining with Perl on the command line== | ==Combining with Perl on the command line== |
Latest revision as of 12:04, 9 January 2017
Template:LowercaseTemplate:Unix
find is a unix program that lists files found recursively under a path.
Contents
Null-terminated output
See null-terminated (console).
Unsorted notes
Until I have time to properly document this, mess with it. Try some of the following:
# Lists files in and below your home directory find ~/
If the path to be searched is ".", that parameter can usually be omitted.
# Lists files in and below the current directory find . # or find
# Lists only the regular files (no dirs, symlinks, pipes, and so on) find . -type f
# Lists only the dirs find . -type d
# Lists regular files and symlinks find . -type f -o -type l # or, as a component to something more complex, find . \( -type f -o -type l \)
To run a command on each path found, use -exec. This example runs md5sum for all regular files (not symlinks, not directories, ...) in and below the current directory, if the read permissions are okay:
find . -type f -exec md5sum {} \; > ../MD5SUMS
The list of files can also be piped to xargs or perl; if using either one, use the -print0 condition on find to use null bytes as delimiters, then use the -0 switch on xargs or perl to expect the same.
# Use \0 as a delimiter instead of \n find . \( -type f -o -type l \) -print0 | perl -n -0 -E 'dosomethingwith($_)'
Using -exec
as a for-each mechanism
The predicate -exec
runs a command for each filename found. When in use, the -print
predicate is no longer implied. -exec
is used as such:
find ... -exec command [someargs] {} [otherargs] ';' ...
For every filename filename found, the command
command [someargs] filename [otherargs]
would be run. The {}
and the ';'
are not optional, while [someargs] and [otherargs] are optional.
Note that when passing arguments to an inline sh/bash script an extra argument should be used to fill the $0 argument if "$@" is being used:
find ... -exec sh -c 'echo "$@"' "$0" {} ';'
find and replace
Using sed:
find ... -exec sed -i.orig 's/PATTERN/REPLACEMENT/g' {} ';'
Using perl:
find ... -exec perl -p -i.orig -e 's/PATTERN/REPLACEMENT/g' {} ';'
Replace -i.orig
with -i
to suppress backups while still changing files in place.
dos2unix/unix2dos
find ... -exec dos2unix {} ';'
find ... -exec unix2dos {} ';'
Call a shell function (bash only)
In bash (but not plain sh) we can export a bash function with export -f
and use it with -exec
via a special invocation of bash:
#!/bin/bash
# Define a function
somefunc() {
...
}
# Export the function to subshells
export -f somefunc
# Call from find
find ... -exec bash -c 'somefunc "$0"' {} ';'
Output relative URIs
Perl's URI::file knows how to convert a local file to a properly escaped URI.
find '...' -print0 | perl -0 -MURI::file -n -E 'chomp; say "".URI::file->new($_)'
Sorting by mtime
find won't sort by mtime by itself. This general command produces a sorted result that should be acceptable by anything that would accept the result of `find … -print0`:
# Let $DESTZ be a command that accepts a list of null-terminated filenames find … -printf '%T@ %p\0' | sort -zk 1n[r] | sed -z 's/^[^ ]* //' | $DESTZ
such as:
find -type f -printf '%T@ %p\0' | sort -zk 1n | sed -z 's/^[^ ]* //' | xargs -0 -i echo 'File: {}'
Breakdown:
# Note that the intermediate processing steps use \0-terminated lists in # order not to lose information about oddly named files. find … -printf '%T@ %p\0' | # Prefixes all files with their numeric mtime and a space sort -zk 1n[r] | # Sorts lines numerically by the prefixes (use `1n` for old to new or `1nr` for new to old) sed -z 's/^[^ ]* //' | # Strips the prefixes from the sorted result $DESTZ # Accepts list of null-terminated filenames
Combining with Perl on the command line
Use perl's -0 switch to allow -print0 to be treated as lines.
This line prints file modified times ((stat(file))[9]
gets the mtime):
find -print0 | perl -n0e '$m=(stat("$_"))[9]; printf(q(%12s %s)."\n",$m,$_)'
You may also find my except-most-recent script handy if you find yourself writing a lot of backup rotation scripts.
See also
- xargs, which turns the output of this program into command line arguments.