How can I exclude all "permission denied" messages from "find"?

Viewed 583650

I need to hide all permission denied messages from:

find . > files_and_folders

I am experimenting when such message arises. I need to gather all folders and files, to which it does not arise.

Is it possible to direct the permission levels to the files_and_folders file?

How can I hide the errors at the same time?

21 Answers

Use:

find . 2>/dev/null > files_and_folders

This hides not just the Permission denied errors, of course, but all error messages.

If you really want to keep other possible errors, such as too many hops on a symlink, but not the permission denied ones, then you'd probably have to take a flying guess that you don't have many files called 'permission denied' and try:

find . 2>&1 | grep -v 'Permission denied' > files_and_folders

If you strictly want to filter just standard error, you can use the more elaborate construction:

find . 2>&1 > files_and_folders | grep -v 'Permission denied' >&2

The I/O redirection on the find command is: 2>&1 > files_and_folders |. The pipe redirects standard output to the grep command and is applied first. The 2>&1 sends standard error to the same place as standard output (the pipe). The > files_and_folders sends standard output (but not standard error) to a file. The net result is that messages written to standard error are sent down the pipe and the regular output of find is written to the file. The grep filters the standard output (you can decide how selective you want it to be, and may have to change the spelling depending on locale and O/S) and the final >&2 means that the surviving error messages (written to standard output) go to standard error once more. The final redirection could be regarded as optional at the terminal, but would be a very good idea to use it in a script so that error messages appear on standard error.

There are endless variations on this theme, depending on what you want to do. This will work on any variant of Unix with any Bourne shell derivative (Bash, Korn, …) and any POSIX-compliant version of find.

If you wish to adapt to the specific version of find you have on your system, there may be alternative options available. GNU find in particular has a myriad options not available in other versions — see the currently accepted answer for one such set of options.

Pipe stderr to /dev/null by using 2>/dev/null

find . -name '...' 2>/dev/null

Redirect standard error. For instance, if you're using bash on a unix machine, you can redirect standard error to /dev/null like this:

find . 2>/dev/null >files_and_folders

Those errors are printed out to the standard error output (fd 2). To filter them out, simply redirect all errors to /dev/null:

find . 2>/dev/null > some_file

or first join stderr and stdout and then grep out those specific errors:

find . 2>&1 | grep -v 'Permission denied' > some_file

Simply use this to search for a file in your system.

find / -name YOUR_SEARCH_TERM 2>&1 | grep YOUR_SEARCH_TERM

Let's not do unnecessary over engineering, you just want to search for your file right? then that is the command which will list the files for you if they are present in an area accessible to you.

Optimized solutions for GNU find

At least for some system+filesystem combinations, find doesn't need to stat a file to get its type. Then you can check if it's a directory before testing readability to speed up the search —I've got some 30% improvement in tests I did. So for long searches or searches that run often enough, use one of these:

Print everything visible

$ find . -print -type d ! -readable -prune
$ find . -type d ! -readable -prune , [expression] -print

Print visible files

$ find . -type d \( ! -readable -prune -o -true \) -o [expression] -print

Print visible directories

$ find . -type d -print ! -readable -prune
$ find . -type d \( ! -readable -prune , [expression] -print \)

Print only readable directories

$ find . -type d ! -readable -prune -o [expression] -print

Notes

The -readable and , (comma) operators are GNU extensions. This expression

$ find . [expression] , [expression]

is logically equivalent to

$ find . \( [expression] -o -true \) [expression]

This is because find implementations with this optimization enabled will avoid stating non-directory files at all in the discussed use case.


Edit: shell function

Here is a POSIX shell function I ended up with to prepend this test to any expression. It seems to work fine with the implicit -print and command-line options:

findr () {
    j=$#; done=
    while [ $j -gt 0 ]; do
        j=$(($j - 1))
        arg="$1"; shift
        test "$done" || case "$arg" in
            -[A-Z]*) ;;  # skip options
            -*|\(|!)     # find start of expression
                set -- "$@" \( -type d ! -readable -prune -o -true \)
                done=true
                ;;
        esac
        set -- "$@" "$arg"
    done
    find "$@"
}

The other two alternatives listed in the answers caused either a syntax error in POSIX shell (couldn't even source a file containing the function definition) or bad output in ZSH... Running time seems to be equivalent.

To search the entire file system for some file, e.g. hosts, except the /proc tree, which causes all kinds of errors, I use the following:

# find / -path /proc ! -prune -o -name hosts -type f
/etc/hosts

Note: Because -prune is always true, you have to negate it to avoid seeing the line /proc in the output. I tried the using ! -readable approach and found it returns all kinds of things under /proc that the current user can read. So the "OR" condition doesn't do what you expect/want there.

I started with the example given by the find man page, See the -prune option.

Minimal solution is just to add the readable flag.

find . -name foo -readable

Related