我无法理解以下结果:
/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:.
我预计PATH
会是空的。
事实上,从某种程度上来说是这样的:
bash-5.0$ /usr/bin/printenv
PWD=/tmp
SHLVL=1
_=/usr/bin/printenv
PATH
所以里面没有环境,但仍然定义了一个非空PATH
变量,并且 shell 可以使用它来解析命令:
bash-5.0$ which ls
/bin/ls
我意识到我可以强制/usr/bin/env
有一个PATH
这样的空:
/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$
我对这种方法有两个问题:1)PATH
显示在/usr/bin/printenv
;的输出中我宁愿它完全消失; 2)上述情况并非独有PATH
;之后/usr/bin/env -i
生成的 shell 会话中的许多变量仍然被定义。
问:/bin/bash
以尽可能少的定义变量(无论是否在环境中)启动交互式会话的最简单方法是什么? 1
(虽然我已经用 来表达这个问题bash
,但我也对有关 的任何相关信息感兴趣zsh
。)
1我知道,如果某些变量未定义,许多程序将无法正常运行,或者根本无法运行。除了故障排除、诊断等之外,我不打算将如此少的 shell 会话用于任何其他用途。
答案1
是的,当在启动时收到的环境中未提供时,bash
两者zsh
(并且dash
和mksh
至少fish
)都设置为默认值。$PATH
不支持的 POSIX shell 仍然需要在默认搜索路径中查找命令。
和(bash
以及zsh
后者中自动加载或不加载的一些模块)设置了许多内部变量,其中一些变量被导出到环境中(尽管在和PATH
的情况下不是),其中一些是只读的。bash
zsh
env -i zsh -f
或者env -i bash --norc
会在空的环境中运行 shell。
要取消设置非只读的,您可以执行unset ${(k)parameters}
inzsh
或unset -v $(compgen -v)
in bash
(尽管我发现我必须运行它两次才能LINES
消失COLUMNS
)。
在我的测试中,bash
仍然剩下:
<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 -- _="_"
并在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
如果未定义 envvar,任何 shell 都将使用“默认”路径(通常至少包括/bin
和/usr/bin
)来查找命令。PATH
这种行为也被复制了execvp(2)
。
一些贝壳(比如巴什) 在这种情况下甚至会将PATH
shell 变量设置为其默认路径。
/bin/bash
以尽可能少的定义变量(无论是否在环境中)启动交互式会话的最简单方法是什么?
env - bash --norc
bash-5.0$ which ls
which
不是内置的 bash —— 在某些系统上,它是由 bash 运行的 shell 脚本不同的shell 比 bash 好。所以这里完全不相关。