Bash 默认把 PATH 传给子 bash,请问是出于什么考虑?

2018-11-30 21:49:32 +08:00
 autumn2018

即使不 export,bash 里再开的 bash(子 bash),也能继承到 PATH 这个 shell 变量,请问,这在平常的脚本编程中有什么用途?不然,bash 为什么这样设计呢?

4739 次点击
所在节点    程序员
33 条回复
jdhao
2018-12-01 13:47:11 +08:00
@momocraft 正解,这一群回答的人基本都是在乱讲,没几个说到点子的
weyou
2018-12-01 15:08:30 +08:00
@jdhao 他都没解,哪里来的“正解”?

“子 bash ”这个叫法虽然很奇怪,但一看就知道是一个 bash 里调用的另一个 bash 啊
jdhao
2018-12-01 15:44:21 +08:00
@weyou 怎么调的?用了什么命令?原文啥都没说
autumn2018
2018-12-01 16:29:30 +08:00
@jdhao
bash-4.3$ a=1
bash-4.3$ PATH=$PATH:xxx
bash-4.3$ echo $PATH
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:xxx
bash-4.3$ echo $a
1
bash-4.3$ bash -norc
bash-4.3$ echo $PATH
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:xxx
bash-4.3$ echo $a

bash-4.3$
no1xsyzy
2018-12-01 17:04:17 +08:00
重点不是传递,而是设置 PATH 会直接修改当前环境变量

no1xsyzy@XSY-New:~$ PATH=foo
no1xsyzy@XSY-New:~$ bash
Command 'bash' is available in '/bin/bash'
The command could not be located because '/bin' is not included in the PATH environment variable.
bash: command not found

而且其他的只要 export 过后修改也会改变环境变量

no1xsyzy@XSY-New:~$ export a=1
no1xsyzy@XSY-New:~$ a=2
no1xsyzy@XSY-New:~$ /usr/bin/env | /bin/grep "^a="
a=2

所以应该是和 @chinvo #15 说的一样,一个变量一但和环境产生关联就会一直绑定。
no1xsyzy
2018-12-01 17:19:15 +08:00
help export
help declare | grep -- -x

export 不是设置环境变量,而是设置变量类型为导出类型,即这个变量的类型是个环境变量。
export foo=bar 只是个语法糖。
先 export -n PATH 这一现象就会消失。

no1xsyzy@XSY-New:~$ export -n PATH
no1xsyzy@XSY-New:~$ PATH=foo
no1xsyzy@XSY-New:~$ bash
Command 'bash' is available in '/bin/bash'
The command could not be located because '/bin' is not included in the PATH environment variable.
bash: command not found
no1xsyzy@XSY-New:~$ /bin/bash -c 'echo $PATH'
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.
iwtbauh
2018-12-01 19:27:00 +08:00
@autumn2018 #24

你并没有在修改 PATH 之前 unset 它,PATH 是环境变量当然会传递给子进程
weyou
2018-12-01 23:21:44 +08:00
@jdhao 不管怎么调的,调用了什么,这个问题的答案都是一样的。一个环境变量只要没有被 unset,都会被所有的子进程(本贴中子 bash 也是子进程)继承。就算被修改了也还是环境变量依然会被继承。
xiaoshenke
2018-12-02 00:18:42 +08:00
因为是环境变量啊 bash 自然是做了特殊处理了
julyclyde
2018-12-02 10:34:55 +08:00
先说结论:
因为 PATH 变量是从上一层继承过来的,默认就是环境变量,所以在 shell 这一层不需要通过 export 命令让它成为环境变量

再说证据:
http://git.savannah.gnu.org/cgit/bash.git/tree/execute_cmd.c 的 execute_disk_command 函数里执行了
exit (shell_execve (command, args, export_env));
其中 export_env 是从 variables.c 里边来的,被 execute_disk_command 调用 shell_execve 之前稍早几句的 maybe_make_export_env (); 写入内容的一个数组

再看 variables.c 文件,maybe_make_export_env 调用了 make_var_export_array,后者又调用了 export_environment_candidate,而最后这个函数只有一句话:
return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
关键在于 imported_p。这个 imported_p 并不是个函数而是一个宏,在 variables.h 里定义的,判断条件里的 att_imported 吸引了我。再搜 att_imported,发现 initialize_shell_variables 函数执行的时候会对部分变量标记 att_imported ( att 即 attribute )

最后说值的继承关系:
在 systemd 为基础的 Linux 发行版里,systemd-exec(5)准备了固定值 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
检查 /proc/pid/environ 可以发现,sshd 和 getty 的 PATH 环境变量值均于此一致
julyclyde
2018-12-02 10:35:41 +08:00
看了看前边的回答,觉得有不少人理解能力有问题
Kobayashi
2018-12-05 17:32:02 +08:00
没有 PATH 变量,外部程序去哪里调用……
momocraft
2018-12-10 10:36:42 +08:00
我又看了一下,PATH 可能是默认就 export 的环境变量 (我机器上用没有.bashrc/.bashprofile 的用户 declare -p PATH 也会看到-x)。

还没有找到这个 export 是在哪个级别决定的 (bash 固定,或哪个全局配置文件)。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/513207

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX