How can I return a list of hidden files readable by the current user in bash without using the -readable flag?

61 Views Asked by At

I want to run a command that outputs all the hidden files the current user can read - in Bash.

So far, I am using the find command, with -perm but I can't seem to get files the current user can read, but files a member of current user's GROUP can read. For testing purposes I am only looking in the /home/ dir. This is achieved with:

find /home/ ! -perm u+r -regextype egrep -regex '^(/.+)*/\..*')' 2>/dev/null

I don't want to use the -readable flag, since it isn't supported in all implementations of find

Is there some magic permissions octal I can use to do this?

1

There are 1 best solutions below

12
On

The relevant standard to which all find implementations must comply is http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html.

That said, -readable was added as an extension to the standard because it adds capabilities that standard find doesn't have. To do without it, we need to compromise either performance or correctness.


Correct But Slow

If you really want to be 100% correct in all cases, consider doing the test external to find, as follows:

find /home -type f -name '.*' '(' -exec test -r '{}' \; ')' -print

This way we're actually testing (vs calculating) readability for every file.


Less Slow (Using Shell-Builtin Evaluation)

find /home -type f -name '.*' -exec sh -c '
  for filename; do test -r "$filename" && printf "%s\n" "$filename"; done
' _ {} +

Instead of starting one copy of test per file, this starts one sh per batch of files (size of each batch depending on the number of filenames that can fit on a command line) and uses the copy of test built into that sh instance to evaluate, and print, those names.


Fast But Imperfect

The following only runs the above, expensive, test on files that don't look readable on account of their explicit file permissions:

find /home -type f -name '.*' \
  '(' \
    '(' \
      '(' -perm -0004 ')' -o \
      '(' -group "$(id -g)" -perm -0040 ')' -o \
      '(' -user  "$(id -u)" -perm -0400 ')' \
    ')' -o '(' -exec test -r '{}' \; ')' \
  ')' -print

That is to say:

  • -perm 0004 matches all files which are world-readable
  • -group "$(id -g)" -perm -0040 matches all files which have the current user's primary group as their group and are group-readable.
  • -user "$(id -u)" -perm -0400 matches all files which are owned by the current user.
  • The final -exec test -r '{}' \; filters for files that are readable despite having passed none of the above tests (for instance, on account of secondary group membership). This test is slow, so we're running it only on files that don't look readable by other means.

This may be inaccurate in unusual corner cases, such as files that have ACLs or other extended permissions modifying their readability.