basherror-handlingfindfile-permissions

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


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?


Solution

  • Note:


    If your shell is bash or zsh, there's a solution that is robust while being reasonably simple, using only POSIX-compliant find features; while bash itself is not part of POSIX, most modern Unix platforms come with it, making this solution widely portable:

    find . > files_and_folders 2> >(grep -v 'Permission denied$' >&2)
    

    Note:

    This approach is:


    POSIX-compliant solutions:

    Fully POSIX-compliant solutions either have limitations or require additional work.

    If find's output is to be captured in a file anyway (or suppressed altogether), then the pipeline-based solution from Jonathan Leffler's answer is simple, robust, and POSIX-compliant:

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

    Note that the order of the redirections matters: 2>&1 must come first.

    Capturing stdout output in a file up front allows 2>&1 to send only error messages through the pipeline, which grep can then unambiguously operate on.

    The only downside is that the overall exit code will be the grep command's, not find's, which in this case means: if there are no errors at all or only permission-denied errors, the exit code will be 1 (signaling failure), otherwise (errors other than permission-denied ones) 0 - which is the opposite of the intent.
    That said, find's exit code is rarely used anyway, as it often conveys little information beyond fundamental failure such as passing a non-existent path.
    However, the specific case of even only some of the input paths being inaccessible due to lack of permissions is reflected in find's exit code (in both GNU and BSD find): if a permissions-denied error occurs for any of the files processed, the exit code is set to 1.

    The following variation addresses that:

    find . 2>&1 >files_and_folders | { grep -v 'Permission denied$' >&2; [ $? -eq 1 ]; }
    

    Now, the exit code indicates whether any errors other than Permission denied occurred: 1 if so, 0 otherwise.
    In other words: the exit code now reflects the true intent of the command: success (0) is reported, if no errors at all or only permission-denied errors occurred.
    This is arguably even better than just passing find's exit code through, as in the solution at the top.


    gniourf_gniourf in the comments proposes a (still POSIX-compliant) generalization of this solution using sophisticated redirections, which works even with the default behavior of printing the file paths to stdout:

    { find . 3>&2 2>&1 1>&3 | grep -v 'Permission denied$' >&3; } 3>&2 2>&1
    

    In short: Custom file descriptor 3 is used to temporarily swap stdout (1) and stderr (2), so that error messages alone can be piped to grep via stdout.

    Without these redirections, both data (file paths) and error messages would be piped to grep via stdout, and grep would then not be able to distinguish between error message Permission denied and a (hypothetical) file whose name happens to end with the phrase Permission denied.

    As in the first solution, however, the the exit code reported will be grep's, not find's, but the same fix as above can be applied.


    Notes on the existing answers: