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.