Finding Files - 3. Actions

Go to the first, previous, next, last section, table of contents.

# 3. Actions

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.

## 3.1 Print File Name

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.

## 3.2 Print File Information

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:

  1. The inode number of the file. See section 2.2.2 Hard Links, for how to find files based on their inode number.
  2. 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 2.4 Size, for how to find files based on their size.
  3. 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 2.5 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 6. File Permissions, for more details about file permissions. See section 2.7 Permissions, for how to find files based on their permissions.
  4. The number of hard links to the file.
  5. The user who owns the file.
  6. The file's group.
  7. The file's size in bytes.
  8. The date the file was last modified.
  9. 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 3.1 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 3.1 Print File Name).

### 3.2.1 Escapes

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).

### 3.2.2 Format Directives

``-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).

#### 3.2.2.1 Name Directives

`%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.

#### 3.2.2.2 Ownership Directives

`%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).

#### 3.2.2.3 Size Directives

`%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.

#### 3.2.2.4 Location Directives

`%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 2.9 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.

#### 3.2.2.5 Time Directives

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 3.2.3 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 3.2.3 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 3.2.3 Time Formats).

### 3.2.3 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.

#### 3.2.3.1 Time Components

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.

#### 3.2.3.2 Date Components

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)

#### 3.2.3.3 Combined Time Formats

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)

## 3.3 Run Commands

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.

### 3.3.1 Single File

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 ';'

### 3.3.2 Multiple Files

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.

#### 3.3.2.1 Unsafe File Name Handling

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

#### 3.3.2.2 Safe File Name Handling

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 3.1 Print File Name).

#### 3.3.2.3 Limiting Command Size

`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.

#### 3.3.2.4 Interspersing File Names

`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 3.3.2.3 Limiting Command Size), this mode of operation is equivalent to ``find -exec'` (see section 3.3.1 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' '{}' ';'

### 3.3.3 Querying

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 3.3.1 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 3.3.2.3 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'`.

## 3.4 Adding Tests

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 \)

Go to the first, previous, next, last section, table of contents.