Typically PATH
is set to an initial value in a highly system-dependent way by the program that logs you in (pam_env
is a common contributor), then /etc/profile
and ~/.profile
and files that they include go on to modify that value.
Remove any change to PATH
in .bashrc
, environment settings don't belong in .bashrc
: see Difference between .bashrc and .bash_profile.
First try logging in in text mode (e.g. with ssh localhost
), as the session startup is a lot simpler than in graphics mode.
Put set -x
at the beginning of /etc/profile
and ~/.profile
. The shell will print a trace of what it does on its standard error stream; look for assignments to PATH
in the trace.
There is no notion of precedence to environment variable assignments: whoever assigns last wins.
If the tool does not do what you want, you can improve it using a wrapper script. I use this script (noenv
) to keep build environments clean. Using it like
sudo -u powerlessuser noenv /bin/processCmd
would do what you're asking. (The script should be in the standard path, otherwise you have to provide it path in the command).
Script:
#!/bin/sh
# $Id: noenv,v 1.3 2014/05/10 22:43:32 tom Exp $
# trim the environment to minimal (PATH may still be long...)
env | sed -e 's/=.*//' -e '/^[ ].*/d' | \
while true
do
read value
if test -z "$value" ; then
# honor assignments to variables in the parameter list
while test $# != 0
do
case "x$1" in
*=*)
eval $1
name=`echo "$1"|sed -e 's/=.*//'`
export $name
shift 1
;;
*)
break
;;
esac
done
exec "$@"
break
fi
case "$value" in
HOME|PATH|USER|_|SHLVL|TMPDIR|LOGNAME)
;;
*\ *|*\(*|*\)*|*\!*)
#echo "...skipping $value"
;;
*)
#echo value:"$value"
unset "$value"
;;
esac
done
To clarify, I did not write this using /usr/bin/env
, because some of the systems on which I was building did not have a POSIX feature which the question mentioned: the -i
option. Those are old BSD systems, including SunOS 4 and HPUX 10 (checking my memory against the manual page for "env" on FreeBSD).
The script, by the way, trims out multi-line values (but the only one you might encounter is TERMCAP
, and that only on very old machines). The second sed-expression is supposed to be a range with tab and space.
For POSIX (which you probably are more interested in), you could do something that uses the feature to pass in selected values from the parent environment, e.g.,
env -i foo="bar"
and so both are customizable. For a large set of variables, that can be clumsy, and a script is a better choice.
sudo
disapproves of TERMCAP
in any case. That is on a (long) list of variables which it helpfully removes from the environment.
sudo
insists on setting certain variables. Reading the source plugins/sudoers/env.c
, you will see this chunk near the end of rebuild_env
:
/* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
CHECK_SETENV2("SUDO_USER", user_name, true, true);
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
CHECK_SETENV2("SUDO_UID", idbuf, true, true);
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
CHECK_SETENV2("SUDO_GID", idbuf, true, true);
debug_return_bool(true);
that is, just before the (only) successful return from that function, it sets its own variables, using its own values.
Best Answer
If you use the
env
command to display the variables, they should show up roughly in the order in which they were created. You can use this as a guide to if they were set by the system very early in the boot, or by a later .profile or other configuration file. In my experience, theset
andexport
commands will sort their variables by alphabetical order, so that listing isn't as useful.