2010年03月04日 星期四 16时38分05秒
在学习LFS 6.6 的第四章第3节(4.3. Adding the LFS User: http://www.linuxfromscratch.org/lfs/view/6.6/chapter04/addinguser.html )时,里面提到登录 shell 和非登录 shell 的概念,不太清楚它们的准确区别,故在 Ubuntu 9.04 下实验了一下。
在Ubuntu 9.04下的试验步骤:
在 Ubuntu 9.04 下的 /etc/profile 中会调用 /etc/bash.bashrc ,所以注释掉其中调用的 /etc/bash.bashrc 后进行试验。
在/etc/profile中写入试验变量: export VAR_TEST=mdx
在/etc/bash.bashrc中写入试验变量: export BASHRC_TEST=bashrc
建立并在~mdx/.bash_profile写入试验变量: export MDXVAR=mdxhome
建立并在~mdx/.bashrc中写入试验变量: export MDXBASHRC=mdxbashrc
按CTRL+ALT+F1登录进入控制台(也可以在X环境的终端下执行 su - mdx 进入登录shell)执行env,存在变量:VAR_TEST=mdx(位于/etc/profile)和MDXVAR=mdxhome(位于~mdx/.bash_profile);
输入bash命令,进入非登录shell(用logout命令退不出来)执行env,存在上面所有4个试验变量;猜测/etc/profile和~mdx/.bash_profile是继承前一个登录shell的变量;
执行exit退出非登录shell状态;
执行logout退出登录shell状态;
用另一个帐号gg重新登录(或 su - gg)进入登录shell执行env,只有变量VAR_TEST=mdx(位于/etc/profile中)存在;
在gg帐号的家目录下创建或写入相应文件:
在 ~gg/.bash_profile中写入试验变量: export MDXVAR=gghome
在 ~gg/.bashrc 中写入试验变量: export MDXBASHRC=ggbashrc
执行logout退出gg帐号的登录shell状态;
用gg帐号重新登录进入登录shell执行env,存在VAR_TEST=mdx(位于/etc/profile中)和MDXVAR=gghome(位于~gg/.bash_profile中) ;
执行 su mdx 进入另一个帐号mdx的非登录shell,执行env,存在VAR_TEST=mdx(位于/etc/profile中,应是继承来的), MDXVAR=gghome(位于~gg/.bash_profile中,可见非登录shell不会读取家目录下的~mdx/.bash_profile,这里的MDXVAR环境变量值应是继承自上面gg的登录shell的) ,MDXBASHRC=mdxbashrc(位于 ~mdx/.bashrc,可见非登录shell读取了家目录下的 ~mdx/.bashrc), BASHRC_TEST=bashrc(位于/etc/bash.bashrc,是非登录shell新读取的,登录shell不会读取这个的);
执行exit退出mdx的非登录shell;
另开一个终端修改/etc/profile中的export VAR_TEST=mdx 为 export VAR_TEST=gg;
在前面mdx退出的终端再执行su mdx登录入非登录shell,执行env,发现VAR_TEST的值仍是mdx而不是已经修改过的gg,可见非登录shell确实是不会读取/etc/profile中的值,而是继承了它的登录父shell的位于/etc/profile中环境变量值;
执行exit退出mdx的非登录shell,再执行su - mdx 进入mdx的登录shell执行env,存在 VAR_TEST=gg(位于/etc/profile中,可见登录shell读取了/etc/profile的值),MDXVAR=mdxhome(位于~mdx/.bash_profile中,可见登录shell读取了家目录下的~mdx/.bash_profile文件)。
综上所述,确实如在Ubuntu 9.04下man bash中所言:
When bash is invoked as an interactive login shell, or as a non-inter-
active shell with the --login option, it first reads and executes com-
mands from the file /etc/profile, if that file exists. After reading
that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile,
in that order, and reads and executes commands from the first one that
exists and is readable. The --noprofile option may be used when the
shell is started to inhibit this behavior.
When a login shell exits, bash reads and executes commands from the
file ~/.bash_logout, if it exists.
When an interactive shell that is not a login shell is started, bash
reads and executes commands from /etc/bash.bashrc and ~/.bashrc, if
these files exist. This may be inhibited by using the --norc option.
The --rcfile file option will force bash to read and execute commands
from file instead of /etc/bash.bashrc and ~/.bashrc.
在登录shell里,确实只读取/etc/profile和~/.bash_profile, ~/.bash_login, and ~/.profile按顺序最先的一个,并执行其中的命令。除非被 --noprofile选项禁止了;
在非登录shell里,确实只读取/etc/bash.bashrc和~/.bashrc,为什么上面在非登录shell里面有登录shell才应有的环境变量值呢?有两个原因:
一、是在登录shell才读的配置文件里调用了非登录shell的配置文件,如Ubuntu 9.04会在/etc/profile中调用/etc/bash.bashrc,如下:
if [ -f /etc/bash.bashrc ]; then
. /etc/bash.bashrc
fi
二、非登录shell作为登录shell的子shell,继承了作为父shell的登录shell的环境变量的值。
在Ubuntu 9.04的X环境下打开终端得到的是一个交互非登录shell,当执行bash时,读取/etc/bash.bashrc and ~/.bashrc。
注意,上面两种shell都是交互式shell,即:交互式的shell会在tty上从用户输入中读取命令. 另一方面, 这样的shell能在启动时读取启动文件, 显示一个提示符, 并默认激活作业控制. 也就是说, 用户可以与shell交互. (参见: 33.1. 交互与非交互式的交互与非交互式的shell和脚本: http://www.tsnc.edu.cn/default/tsnc_wgrj/doc/abs-3.9.1_cn/html/intandnonint.html ),非交互式的shell(如 Linux 系统启动时初始化脚本和启动脚本)有另外的特性这里没有提及;
另外,上面提到的子shell会继承父shell的环境变量。不过,shell程序里面除了环境变量还有与 bash 操作界面有关的变量(如:PS1)和自定义变量,而父shell的自定义变量是不会被它的子shell继承的(参见: export: 自訂變數轉成環境變數 http://linux.vbird.org/linux_basic/0320bash.php#export )!另外,与bash操作界面有关的变量也不会被继承,如:PS1等。我是这样测试的:修改/etc/bash.bashrc中PS1的值; . /etc/bash.bashrc 使其生效;重命名/etc/bash.bashrc,这样下一个非登录shell不会读到其中的值和执行其中的设定;执行bash命令进入非登录子shell,会发现提示符并没有继承父shell的值。假如要让子 bash shell 继承父 bash shell 的 PS1 值(即在不存在 /etc/bash.bashrc 等自动设置 PS1 的情况下让子 bash shell 的提示符与父 bash shell 相同),同样可以用 export 命令把父 bash shell 中的 PS1 转换为环境变量。