0

I cannot make sense of the results below:

/tmp/% /usr/bin/env -i /bin/bash --norc --noprofile
bash-5.0$ echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.

I expected PATH to be empty.

Actually, in a way it is:

bash-5.0$ /usr/bin/printenv
PWD=/tmp
SHLVL=1
_=/usr/bin/printenv

So there's no PATH in the environment, but a non-empty PATH variable is still defined, and can be used by the shell to resolve commands:

bash-5.0$ which ls
/bin/ls

I realize that I can force /usr/bin/env to have an empty PATH like this:

/tmp/% /usr/bin/env -i PATH= /bin/bash --norc --noprofile
bash-5.0$ /usr/bin/printenv
PWD=/tmp
SHLVL=1
PATH=
_=/usr/bin/printenv
bash-5.0$ echo $PATH

bash-5.0$ 

I have two problems with this approach: 1) PATH is shows in the output of /usr/bin/printenv; I'd prefer it if it were completely gone; 2)the situation described above is not unique to PATH; after /usr/bin/env -i a lot of variables in the resulting shell session are still defined.

Q: What is the simplest way to start an interactive /bin/bash session with the least possible number of variables defined (whether in the environment or not)? 1

(Though I've phrased this question in terms of bash, I'm also interested in any related info regarding zsh.)


1 I am aware of the fact that many programs will not function normally, or function at all, if some variables are undefined. I do not intend to use such minimal shell sessions for anything other than for troubleshooting, diagnostics, and the like.

4
2

Yes, both bash and zsh (and dash and mksh and fish at least) set $PATH to a default value when not supplied in the environment they received on startup.

The POSIX shells that don't are still required to look up commands in a default search path.

Both bash and zsh (and some of the modules that are loaded automatically or not in the latter) set a number of internal variables some of which are exported to the environment (not PATH though in the case of bash and zsh), some of which are read-only.

env -i zsh -f or env -i bash --norc would run the shell with an empty environ.

To unset the non-readonly ones, you can do unset ${(k)parameters} in zsh or unset -v $(compgen -v) in bash (though I find that I have to run it twice for LINES and COLUMNS to disappear).

In my test, in bash, that still leaves:

<noprompt> typeset -p
declare -r BASHOPTS="checkwinsize:cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:globasciiranges:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath"
declare -a BASH_ARGC=([0]="0")
declare -a BASH_ARGV=()
declare -a BASH_LINENO=()
declare -a BASH_SOURCE=()
declare -ar BASH_VERSINFO=([0]="5" [1]="0" [2]="17" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
declare -ir EUID="1000"
declare -a FUNCNAME
declare -x OLDPWD
declare -a PIPESTATUS=([0]="1")
declare -ir PPID="44873"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="1000"
declare -- _="_"

And in zsh:

<noprompt> printf '%s (%s)\n' ${(kv)parameters}
parameters (association-readonly-hide-hideval-special)
HISTCMD (integer-readonly-special)
! (integer-readonly-special)
# (integer-readonly-special)
$ (integer-readonly-special)
* (array-readonly-special)
- (scalar-readonly-special)
0 (scalar-special)
ZSH_EVAL_CONTEXT (scalar-readonly-tied-special)
ZSH_SUBSHELL (integer-readonly-special)
? (integer-readonly-special)
@ (array-readonly-special)
zsh_eval_context (array-readonly-tied-special)
status (integer-readonly-special)
TTYIDLE (integer-readonly-special)
LINENO (integer-readonly-special)
PPID (integer-readonly-special)
ARGC (integer-readonly-special)
2

Any shell will use a "default" path (usually including at least /bin and /usr/bin) to lookup commands if the PATH envvar isn't defined. That behaviour is also replicated by execvp(2).

Some shells (like bash) will even set the PATH shell variable to their default path in that case.

What is the simplest way to start an interactive /bin/bash session with the least possible number of variables defined (whether in the environment or not)?

env - bash --norc

bash-5.0$ which ls

which is not a bash built-in -- on some systems it's a shell script run by a different shell than bash. So it's completely irrelevant here.

2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.