Find not returning expected files

find

I'm trying to find some large files in a specific location:

This command works and returns some results:

admin@tyrell:~$ sudo find /nfshome/*/.local/ -type f -size +1G -exec ls -lh {} \;
-rw-r--r-- 1 9917183 students 5.2G Jun  5  2017 /nfshome/9917183/.local/share/Trash/files/result_25.zip
-rw-r--r-- 1 9918178 students 4.0G Sep  6  2018 /nfshome/9918178/.local/share/unity3d/Asset Store-5.x/Unity Technologies/Unity EssentialsSample Projects/3D Game Kit.unitypackage
-rw-r--r-- 1 9919185 students 2.1G Mar  6  2018 /nfshome/9919185/.local/share/Trash/files/agggg.avi
-rw-r--r-- 1 9919382 students 1.7G Jan 17  2017 /nfshome/9919382/.local/share/Trash/files/MageWar.avi
-rw-r--r-- 1 9921459 students 1.8G Apr 12 11:58 /nfshome/9921459/.local/share/Trash/files/takeout-20190412T182950Z-001(1).zip
-rw-r--r-- 1 9921459 students 1.8G Apr 12 11:58 /nfshome/9921459/.local/share/Trash/files/takeout-20190412T182950Z-001.zip
-rw-r--r-- 1 9921459 students 1.4G Apr 12 11:56 /nfshome/9921459/.local/share/Trash/files/takeout-20190412T182950Z-003.zip
-rw-r--r-- 1 9921459 students 1.4G Apr 12 11:58 /nfshome/9921459/.local/share/Trash/files/takeout-20190412T182950Z-003(1).zip

but if I try to narrow the search by adding one more subdirectory, share/, I get nothing, where I would expect to get the exact same result, because everything above is in share/:

admin@tyrell:~$ sudo find /nfshome/*/.local/share/ -type f -size +1G -exec ls -lh {} \;
admin@tyrell:~$ 

Why doesn't find return the same result as the first command?

Best Answer

The reason this fails is to do with permissions and the wildcard * character. We can reproduce this on a local file-system like this:

  1. Set up the scenario, a directory tree under /tmp/top:

    sudo -s <<'x'
    mkdir -p /tmp/top/{a,b}/dir/sub/
    touch /tmp/top/{a,b}/dir/sub/file
    chown root /tmp/top/?/dir
    chmod go= /tmp/top/?/dir
    x
    
  2. Notice that we have no permission as an ordinary user to go below /tmp/top/*/dir:

    find /tmp/top/?/dir -type f
    find: ‘/tmp/top/a/dir’: Permission denied
    find: ‘/tmp/top/b/dir’: Permission denied
    
  3. Try descending with root privileges from a directory that we cannot reach as an ordinary user:

    sudo find /tmp/top/*/dir/sub -type f
    find: ‘/tmp/top/*/dir/sub’: No such file or directory
    

    Remember the evaluation of shell wildcards happens before the command is executed. So what is happening here is that the path containing the wildcard * is expanded. Your ordinary user account cannot verify the existence of sub, and so the entire path cannot be verified. The wildcard remains as an asterisk (the default behaviour when a match fails) and the root privileged find is given the literal path /tmp/top/*/dir/sub to descend. This path does not exist, hence the error.

  4. Try descending with root privileges from a directory that we can reach as an ordinary user:

    sudo find /tmp/top/*/dir -type f
    /tmp/top/a/dir/sub/file
    /tmp/top/b/dir/sub/file
    

    What happens here is similar, but with more useful consequences. The path /tmp/top/*/dir can be evaluated completely as your ordinary user, resulting in two paths /tmp/top/a/dir and /tmp/top/b/dir. These are passed to the root privileged find, and it can subsequently descend these - through the root-only subdirectory - and list the files it discovers.

In your situation, it is highly likely that the .local directories in your wildcarded path cannot be accessed without root privileges, but the higher level directories are quite accessible. While you specify a path that can be evaluated as your ordinary user account, the find can proceed with the expanded set of paths. As soon as you specify a path that cannot be evaluated in the context of your ordinary user account, the expansion fails and find is passed a path that contains a literal * character. This of course fails to match and the find fails.

To resolve the issue you simply need to defer the evaluation of the path until your command is running as root:

sudo bash -c "find /nfshome/*/.local/ -type f -size +1G -exec ls -lh {} \;"
Related Question