|
Go to the previous, next chapter.
There are several ways you can print information about the files that match the
criteria you gave in the find expression. You can print the information
either to the standard output or to a file that you name. You can also execute commands
that have the file names as arguments. You can use those commands as further filters to
select files.
- Action: -print True; print the full file name on the standard output, followed by a
newline.
- Action: -fprint file True; print the full file name into file file,
followed by a newline. If file does not exist when find is run, it
is created; if it does exist, it is truncated to 0 bytes. The file names /dev/stdout
and /dev/stderr are handled specially; they refer to the standard output and
standard error output, respectively.
- Action: -ls True; list the current file in ls -dils format on the
standard output. The output looks like this:
204744 17 -rw-r--r-- 1 djm staff 17337 Nov 2 1992 ./lwall-quotes
The fields are:
- The inode number of the file. See section Hard Links, for
how to find files based on their inode number.
- the number of blocks in the file. The block counts are of 1K blocks, unless the
environment variable
POSIXLY_CORRECT is set, in which case 512-byte blocks
are used. See section Size, for how to find files based on
their size.
- The file's type and permissions. The type is shown as a dash for a regular file; for
other file types, a letter like for -type is used (see section Type). The permissions are read, write, and execute for the
file's owner, its group, and other users, respectively; a dash means the permission is not
granted. See section File Permissions, for more details
about file permissions. See section Permissions, for how to
find files based on their permissions.
- The number of hard links to the file.
- The user who owns the file.
- The file's group.
- The file's size in bytes.
- The date the file was last modified.
- The file's name. -ls quotes non-printable characters in the file names
using C-like backslash escapes.
- Action: -fls file True; like -ls but write to file like -fprint
(see section Print File Name).
- Action: -printf format True; print format on the standard output,
interpreting \ escapes and % directives. Field widths and
precisions can be specified as with the printf C function. Unlike -print,
-printf does not add a newline at the end of the string.
- Action: -fprintf file format True; like -printf but write to file
like -fprint (see section Print File Name).
The escapes that -printf and -fprintf recognize are:
- \a Alarm bell. \b Backspace. \c Stop printing from this format
immediately and flush the output. \f Form feed. \n Newline. \r
Carriage return. \t Horizontal tab. \v Vertical tab. \\ A literal
backslash (\).
A \ character followed by any other character is treated as an ordinary
character, so they both are printed, and a warning message is printed to the standard
error output (because it was probably a typo).
-printf and -fprintf support the following format directives
to print information about the file being processed. Unlike the C printf
function, they do not support field width specifiers.
%% is a literal percent sign. A % character followed by any
other character is discarded (but the other character is printed), and a warning message
is printed to the standard error output (because it was probably a typo).
- %p File's name. %f File's name with any leading directories removed (only
the last element). %h Leading directories of file's name (all but the last element
and the slash before it). %P File's name with the name of the command line argument
under which it was found removed from the beginning. %H Command line argument under
which file was found.
- %g File's group name, or numeric group ID if the group has no name. %G
File's numeric group ID. %u File's user name, or numeric user ID if the user has no
name. %U File's numeric user ID. %m File's permissions (in octal).
- %k File's size in 1K blocks (rounded up). %b File's size in 512-byte
blocks (rounded up). %s File's size in bytes.
- %d File's depth in the directory tree; files named on the command line have a
depth of 0. %F Type of the filesystem the file is on; this value can be used for -fstype
(see section Directories). %l Object of symbolic
link (empty string if file is not a symbolic link). %i File's inode number (in
decimal). %n Number of hard links to file.
Some of these directives use the C ctime function. Its output depends on
the current locale, but it typically looks like
Wed Nov 2 00:42:36 1994
- %a File's last access time in the format returned by the C
ctime
function. %Ak File's last access time in the format specified by k
(see section Time Formats). %c File's last status
change time in the format returned by the C ctime function. %Ck
File's last status change time in the format specified by k (see section Time Formats). %t File's last modification time in the
format returned by the C ctime function. %Tk File's last
modification time in the format specified by k (see section Time Formats).
Below are the formats for the directives %A, %C, and %T,
which print the file's timestamps. Some of these formats might not be available on all
systems, due to differences in the C strftime function between systems.
The following format directives print single components of the time.
- H hour (00..23) I hour (01..12) k hour ( 0..23) l hour (
1..12) p locale's AM or PM Z time zone (e.g., EDT), or nothing if no time
zone is determinable M minute (00..59) S second (00..61) @ seconds
since Jan. 1, 1970, 00:00 GMT.
The following format directives print single components of the date.
- a locale's abbreviated weekday name (Sun..Sat) A locale's full weekday
name, variable length (Sunday..Saturday) b h locale's abbreviated month name
(Jan..Dec) B locale's full month name, variable length (January..December) m
month (01..12) d day of month (01..31) w day of week (0..6) j day of
year (001..366) U week number of year with Sunday as first day of week (00..53) W
week number of year with Monday as first day of week (00..53) Y year (1970...) y
last two digits of year (00..99)
The following format directives print combinations of time and date components.
- r time, 12-hour (hh:mm:ss [AP]M) T time, 24-hour (hh:mm:ss) X
locale's time representation (H:M:S) c locale's date and time (Sat Nov 04 12:02:33
EST 1989) D date (mm/dd/yy) x locale's date representation (mm/dd/yy)
You can use the list of file names created by find or locate
as arguments to other commands. In this way you can perform arbitrary actions on the
files.
Here is how to run a command on one file at a time.
- Action: -exec command ; Execute command; true if 0 status is returned. find
takes all arguments after -exec to be part of the command until an argument
consisting of ; is reached. It replaces the string {} by the
current file name being processed everywhere it occurs in the command. Both of these
constructions need to be escaped (with a \) or quoted to protect them from
expansion by the shell. The command is executed in the directory in which find
was run.
For example, to compare each C header file in the current directory with the file /tmp/master:
find . -name '*.h' -exec diff -u '{}' /tmp/master ';'
Sometimes you need to process files alone. But when you don't, it is faster to run a
command on as many files as possible at a time, rather than once per file. Doing this
saves on the time it takes to start up the command each time.
To run a command on more than one file at once, use the xargs command,
which is invoked like this:
xargs [option...] [command [initial-arguments]]
xargs reads arguments from the standard input, delimited by blanks (which
can be protected with double or single quotes or a backslash) or newlines. It executes the
command (default is /bin/echo) one or more times with any initial-arguments
followed by arguments read from standard input. Blank lines on the standard input are
ignored.
Instead of blank-delimited names, it is safer to use find -print0 or find
-fprint0 and process the output by giving the -0 or --null
option to GNU xargs, GNU tar, GNU cpio, or perl.
You can use shell command substitution (backquotes) to process a list of arguments,
like this:
grep -l sprintf `find $HOME -name '*.c' -print`
However, that method produces an error if the length of the .c file names
exceeds the operating system's command-line length limit. xargs avoids that
problem by running the command as many times as necessary without exceeding the limit:
find $HOME -name '*.c' -print | grep -l sprintf
However, if the command needs to have its standard input be a terminal (less,
for example), you have to use the shell command substitution method.
Because file names can contain quotes, backslashes, blank characters, and even
newlines, it is not safe to process them using xargs in its default mode of
operation. But since most files' names do not contain blanks, this problem occurs only
infrequently. If you are only searching through files that you know have safe names, then
you need not be concerned about it.
In many applications, if xargs botches processing a file because its name
contains special characters, some data might be lost. The importance of this problem
depends on the importance of the data and whether anyone notices the loss soon enough to
correct it. However, here is an extreme example of the problems that using blank-delimited
names can cause. If the following command is run daily from cron, then any
user can remove any file on the system:
find / -name '#*' -atime +7 -print | xargs rm
For example, you could do something like this:
eg$ echo > '#
vmunix'
and then cron would delete /vmunix, if it ran xargs
with / as its current directory.
To delete other files, for example /u/joeuser/.plan, you could do this:
eg$ mkdir '#
'
eg$ cd '#
'
eg$ mkdir u u/joeuser u/joeuser/.plan'
'
eg$ echo > u/joeuser/.plan'
/#foo'
eg$ cd ..
eg$ find . -name '#*' -print | xargs echo
./# ./# /u/joeuser/.plan /#foo
Here is how to make find output file names so that they can be used by
other programs without being mangled or misinterpreted. You can process file names
generated this way by giving the -0 or --null option to GNU xargs,
GNU tar, GNU cpio, or perl.
- Action: -print0 True; print the full file name on the standard output, followed by a
null character.
- Action: -fprint0 file True; like -print0 but write to file
like -fprint (see section Print File Name).
xargs gives you control over how many arguments it passes to the command
each time it executes it. By default, it uses up to ARG_MAX - 2k, or 20k,
whichever is smaller, characters per command. It uses as many lines and arguments as fit
within that limit. The following options modify those values.
- --no-run-if-empty -r If the standard input does not contain any nonblanks,
do not run the command. By default, the command is run once even if there is no input.
- --max-lines[=max-lines] -l[max-lines] Use at most max-lines
nonblank input lines per command line; max-lines defaults to 1 if omitted.
Trailing blanks cause an input line to be logically continued on the next input line, for
the purpose of counting the lines. Implies -x.
--max-args=max-args
-n max-args Use at most max-args arguments per command line.
Fewer than max-args arguments will be used if the size (see the -s
option) is exceeded, unless the -x option is given, in which case xargs
will exit.
--max-chars=max-chars -s max-chars Use at most max-chars
characters per command line, including the command and initial arguments and the
terminating nulls at the ends of the argument strings.
--max-procs=max-procs -P max-procs Run up to max-procs
processes at a time; the default is 1. If max-procs is 0, xargs
will run as many processes as possible at a time. Use the -n, -s,
or -l option with -P; otherwise chances are that the command
will be run only once.
xargs can insert the name of the file it is processing between arguments
you give for the command. Unless you also give options to limit the command size (see
section Limiting Command Size), this mode of operation is
equivalent to find -exec (see section Single File).
- --replace[=replace-str] -i[replace-str] Replace
occurences of replace-str in the initial arguments with names read from
standard input. Also, unquoted blanks do not terminate arguments. If replace-str
is omitted, it defaults to {} (like for find -exec). Implies -x
and -l 1. As an example, to sort each file the bills directory,
leaving the output in that file name with .sorted appended, you could do:
find bills -type f | xargs -iXX sort -o XX.sorted XX
The equivalent command using find -exec is:
find bills -type f -exec sort -o '{}.sorted' '{}' ';'
To ask the user whether to execute a command on a single file, you can use the find
primary -ok instead of -exec:
- Action: -ok COMMAND ; Like -exec (see section Single
File), but ask the user first (on the standard input); if the response does not start
with y or Y, do not run the command, and return false.
When processing multiple files with a single command, to query the user you give xargs
the following option. When using this option, you might find it useful to control the
number of files processed per invocation of the command (see section Limiting Command Size).
- --interactive -p Prompt the user about whether to run each command line
and read a line from the terminal. Only run the command line if the response starts with y
or Y. Implies -t.
You can test for file attributes that none of the find builtin tests
check. To do this, use xargs to run a program that filters a list of files
printed by find. If possible, use find builtin tests to pare
down the list, so the program run by xargs has less work to do. The tests
builtin to find will likely run faster than tests that other programs
perform.
For example, here is a way to print the names of all of the unstripped binaries in the /usr/local
directory tree. Builtin tests avoid running file on files that are not
regular files or are not executable.
find /usr/local -type f -perm +a=x | xargs file |
grep 'not stripped' | cut -d: -f1
The cut program removes everything after the file name from the output of file.
If you want to place a special test somewhere in the middle of a find
expression, you can use -exec to run a program that performs the test.
Because -exec evaluates to the exit status of the executed program, you can
write a program (which can be a shell script) that tests for a special attribute and make
it exit with a true (zero) or false (non-zero) status. It is a good idea to place such a
special test after the builtin tests, because it starts a new process which could
be avoided if a builtin test evaluates to false. Use this method only when xargs
is not flexible enough, because starting one or more new processes to test each file is
slower than using xargs to start one process that tests many files.
Here is a shell script called unstripped that checks whether its argument
is an unstripped binary file:
#!/bin/sh
file $1 | grep 'not stripped' > /dev/null
This script relies on the fact that the shell exits with the status of the last program
it executed, in this case grep. grep exits with a true status if
it found any matches, false if not. Here is an example of using the script (assuming it is
in your search path). It lists the stripped executables in the file sbins and the
unstripped ones in ubins.
find /usr/local -type f -perm +a=x \
\( -exec unstripped '{}' \; -fprint ubins -o -fprint sbins \)
|