基本概念
登录(Login) shell
A login shell is one whose first character of argument zero is a -, or one started with the –login option.
登录系统时的 shell,作为登录系统的一部分运行,通常用于环境变量的配置.
用户登陆后运行的其他任何 shell,被称为非登录(Non-login)shell.
交互式(Interactive)shell
An interactive shell is one started without non-option arguments (unless -s is specified) and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state.
可以进行命令交互的 shell,交互式 shell 通常从用户终端读取和写入.
相反,脚本或者其他进程启动的、不可交互的被称为非交互式(Non-interactive)shell.
远程(Remote)shell
Bash attempts to determine when it is being run with its standard input connected to a network connection, as when executed by the remote shell daemon, usually
rshd
, or the secure shell daemonsshd
. If Bash determines it is being run in this fashion, it reads and executes commands from ~/.bashrc, if that file exists and is readable. It will not do this if invoked assh
. The--norc
option may be used to inhibit this behavior, and the--rcfile
option may be used to force another file to be read, but neitherrshd
norsshd
generally invoke the shell with those options or allow them to be specified.
远程 shell 指通过网络远程启动 shell,它是非登录且非交互式的.
.bash_profile | .bash_login | .profile
在登录 shell 中,Bash 首先查找 /etc/profile
文件,加载全局环境配置.
然后 Bash 会在家目录中按顺序查找 .bash_profile
、.bash_login
和 .profile
,并仅执行第一个可读文件.
.bashrc
.bashrc
是 Bash shell 的配置文件,一般用于存放别名或者函数.
为了保证用户环境的一致性,大部分发行版的 .profile
都会默认引用 .bashrc
.
Bash 行为参考
L | I | R | inh | p | rc | Example | ||
---|---|---|---|---|---|---|---|---|
• | • | - | • | ssh host.com (sshd sets argv[0]=”-bash”) |
||||
• | - | • | ssh host.com </dev/null (sshd sets argv[0]=”-bash”) |
|||||
• | • | • | bash -i , bash on tty |
|||||
• | bash hello.sh , bash -c echo foo , |
|||||||
• | • | ssh host.com 'echo $-' (ssh runs bash -c 'echo $-' ) |
- ‘•’ = 是; blank = 否; ‘-‘ = 不重要.
- inh: 从父进程继承的环境.
- p: 加载
/etc/profile
和~/.bash_profile
,~/.bash_login
,~/.profile
顺序中的第一个. - rc: 加载
/etc/bash.bashrc
和~/.bashrc
补充说明
远程 shell
作为一种特殊情况,远程 shell 无论如何都会加载 .bashrc
.
大多数发行版的 .bashrc
都会在开头判断避免被加载,如:
1 | # If not running interactively, don't do anything |
或者
1 | # If not running interactively, don't do anything |
远程文件传输失败
对于使用远程 shell 传输数据的程序(例如 rcp
、 scp
和 sftp
)来说,远程用户的 .bashrc
会被加载,而因为 scp
和 sftp
有自己用于交换传输文件信息协议,.bashrc
中输出的任何意外文本都会被错误引入而影响传输.
交互式环境检查
echo $-
的返回中包含 i
的话说明当前为交互式 shell.
1 | $ echo $- |
管道(og-apus)
1 | client, err = ssh.Dial("tcp", net.JoinHostPort(sshConf.Server, sshConf.Port), remoteConfig) |
在 go 中通过 ssh 建立的 session 本身是交互式的,但是直接执行的命令都属于远程 shell,所以会加载用户环境中 .bashrc
文件中交互式判断之前的内容.
webshell 属于 tty,所以是交互式的.
Slurm
How does Slurm establish the environment for my job?
Slurm processes are not run under a shell, but directly exec’ed by the slurmd daemon (assuming srun is used to launch the processes). The environment variables in effect at the time the srun command is executed are propagated to the spawned processes. The ~/.profile and ~/.bashrc scripts are not executed as part of the process launch. You can also look at the –export option of srun and sbatch. See man pages for details.
Slurm 进程不在 shell 下运行,而是由 slurmd 守护进程直接执行,通过 srun
运行作业时直接继承执行时的环境,既不会加载 .profile
也不会加载 .bashrc
.
ref: slurm FAQ
通过管道提交 Slurm 作业
由于管道提交的作业是非交互式的,且 Slurm 会继承此环境,在作业模板中 source ~/.bashrc
大多情况下也会被判断拦截,所以用户作业所需要的环境初始化过程(如 conda init)都需要在作业模板中执行一次.
Simple Hack
1 | # ssh remote_node "bash -l -c 'which mmsetquota'" |
bash -l -c
可以模拟登录流程加载profile.d
中的环境变量(仍然会跳过.bashrc
中的有小部分,因为子 shell 是非交互式的)