Bash 初始化文件

交互式 login shell

在下列情况下,我们可以获得一个 login shell

  • 登录系统时获得的顶层 shell ,无论是通过本地终端登录,还是通过网络 ssh 登录。这种情况下获得的 login shell 是一个交互式 shell
  • 在终端下使用 --login 选项调用 bash ,可以获得一个交互式 login shell
  • 在脚本中使用 --login 选项调用 bash (例如: #!/bin/bash --login )可以得到一个非交互式的 login shell
  • 使用 su - 切换到指定用户时,获得此用户的 login shell 。如果不使用 - ,则获得 non-login shell

login shell 启动时首先读取 /etc/profile 系统全局配置,然后依次查找 ~/.bash_profile~/.bash_login~/.profile 三个配置文件,并且读取首个找到的并且可读的文件。 login shell 退出时读取并执行 ~/.bash_logout 中的命令。 如果配置文件存在但不可读,则会显示错误消息;如果文件不存在, bash 将自动搜索下一个文件。

[!1info] 默认的 /etc/profile 会定义 PATHUSERMAILHOSTNAMEHISTSIZE 等全局环境变量,还会自动导入 /etc/bash.bashrc 文件(包含系统级 shell 函数和别名),以及 /etc/profile.d 路径下被用于针对特定程序进行初始化的所有 *.sh 文件。

交互式 non-login shell

非登录 shell 意味着在启动时不必通过系统身份验证。 GUI 中用户打开的终端默认为非登录 shell ,可以通过 logout 命令判断:

# 在Ubuntu GUI桌面打开一个终端
> logout
bash: logout: not login shell: use `exit'
> bash --login
> logout  # 正常登出 什么也不会输出

非登录 shell 在初始化时仅读取 ~/.bashrc 资源文件。

[!1INFO] ~/.bashrc 文件会自动被 ~/.bash_profile~/.profile 加载,因此为了保证 login shell 和交互式 non-login shell 得到相同的配置,一般将环境变量定义在 ~/.bashrc 文件中。

> echo "export sflag=\"login shell will see this message\"" >> ~/.profile    
> bash  
> echo $sflag  
                    # 找不到这个变量 会打印一个空行
> exit  
> bash --login  
> echo $sflag  
login shell will see this message  
> logout

非交互式 shell

通过 bash 命令执行脚本时会以非交互( non-interactively )的方式启动 shell ,这保证了在脚本执行过程中不会被用户干扰。在非交互式脚本启动时,仅会加载 BASH_ENV 变量指向的文件。

[!1WARN] 由于 PATH 变量默认不会被非交互式 shell 加载,因此变量 BASH_ENV 的值应该为绝对路径。

通过特殊变量 - 可以查看当前shell的模式:

> echo $-
himBHs  # 带有'i'就是交互式shell

另一个简单的方式是检查当前 shell 中是否存在提示符环境变量 PS1 .

if [ -z "$PS1" ]; then echo "非交互式";else echo "交互式";fi

特殊情况

兼容模式

如果使用命令 sh 调用 bash ,则为了保证兼容性会按照 sh 的方式对 bash 进行初始化。作为 login shell 启动时, bash 依次读取 /etc/profile~/.profile 配置文件。作为 non-login shell 启动时, bash 仅会读取环境变量 ENV 指向的文件。

POSIX 模式

当通过以下方式启动 bash 时:

  • 设置 set -o posixexport POSIXLY_CORRECT=1
  • bash --posix

bash 会尽可能按照 POSIX 标准进行初始化,仅会读取环境变量 ENV 指向的文件。

远程启动脚本

使用 rshd 远程启动脚本时仅会加载 ~/.bashrc 文件,但要注意的是尽量不要使用 rlogin, telnet, rsh, rcp 等远程命令,因为这些命令会传输未加密的明文信息。如果有远程访问需求尽量使用SSH

UID 与 EUID 不匹配

如果我们给 bash 设置 set-user-id 标志,那么由于其默认所有者为 root ,当其他非 root 用户运行 bash 时,该进程的 UID 将不等于 EUID ,这种情况下为了保证安全性, bash 在初始化阶段不会加载任何文件。

[!1INFO] Linux 内核会为每个进程维护 task_struct 用于记录进程运行时所需要的信息, 其中 UID (真实用户ID)用于记录创建进程的用户的 UIDEUID (有效用户ID)用于判断当前进程对文件的访问级别,一般情况下 UID = EUID 。如果可执行文件的 set-user-id: SUID 位有效(例如: /usr/bin/passwd 的权限为 -rwsr-xr-x ,用户级别的 x 被替换为 s ),表示当该文件被执行时,进程具有文件所有者的权限而不是创建者的权限, 这时 EUID 的值为文件所有者的 UID , 而不是进程创建者的 UID .

受限制的 shell

通过 rbashbash --restrictedbash -r 启动时会生成功能受限制的shell,具体表现为:

  • 不能使用 cd 命令并且命令中不能包含 /
  • 不能更改 SHELLPATHENVBASH_ENV 环境变量
  • source 命令的参数也不能包含带有 / 的文件
  • hash –p <path> <name> 用于给路径起别名的命令的参数中也不能包含 /
  • 初始化时不会导入文件中的函数并且会忽略 SHELLOPTS
  • 不能使用重定向
  • 不能使用 exec 命令
  • 不能使用 enable -f/-d 增加删除命令
  • 不能使用 command -p 指定运行命令需要的路径
  • 不能主动关闭限制模式

这个功能理论上可以让用户在指定的文件夹内执行指定的文件来完成有限的功能,但是如果环境变量设置不当会导致用户很轻松地就能解除限制:

> rbash
> cd /etc
rbash: cd: restricted
> bash
> cd /etc  # 可以成功执行,因为这个时候我们在bash环境中,没有任何限制

一种有效的做法是给新建的用户的能执行的命令作出限制,例如我们可以新建一个只能执行 ftp 命令的 ruser

> useradd -s /bin/rbash ruser  # 设置用户登录时提供的shell
> chown -R root:ruser /home/ruser/.bashrc /home/ruser/.bash_profile
# 设置root为拥有者,ruser组为组拥有者(新建的ruser默认输入ruser组)
> chmod 640 /home/ruser/.bashrc /home/ruser/.bash_profile
# root可以读写,ruser组里的用户只读,其他用户什么也不能干
> mkdir /home/ruser/bin  # 存储用户的可执行文件或链接
> echo "export PATH=/home/ruser/bin" >> /home/ruser/.bash_profile
> ln -s /user/bin/ftp /home/ruser/bin/ftp

参考内容

results matching ""

    No results matching ""