In a `sudo find` command, how do I make sure that `-exec` command is run as normal user?

On systems that support it (GNU and quite a few others), you could do:

sudo find /path/ -print0 | xargs -r0 process_paths

xargs is not run under sudo, so it still has the original uids/gids and also the original environment (in the larger sense), not the one modified by sudo.

process_paths stdin ends up being modified though (depending on the xargs implementation, it's open on /dev/null or shares the pipe from sudo/find.

To avoid that (with GNU xargs and shells like ksh, zsh or bash that support process substitution), you could do:

xargs -r0a <(sudo find /path/ -print0) process_paths

With zsh:

sudo zsh -c '
   files=(/path/**/*(D))
   USERNAME=$SUDO_USER
   autoload zargs
   zargs $files -- process_paths'

In zsh, assigning a user name to the $USERNAME special variable, sets the uids, gids to that of the corresponding user in the user database like sudo -u "$SUDO_USER" would do.

You could do:

 sudo sh -c '
   exec find /path/ -exec sudo -u "$SUDO_USER" process_paths {} +'

But because sudo passes a $SUDO_COMMAND environment variable (which contains the concatenation of the arguments with spaces) to process_paths, the list of files ends up being passed twice to process_paths which means the limit on the maximum size of args+env is likely to be reached if there's a large number of files.

With most su implementations, you should be able to do:

 sudo sh -c '
   exec find /path/ -exec su "$SUDO_USER" -c '\''
     exec "$0" "$@"'\'' process_paths {} +'

though as su doesn't have the same issue.

Tags:

Find

Sudo

Su