我了解交互式 shell 和非交互式 shell 之间的基本区别。但是登录 shell 和非登录 shell 到底有什么区别呢?
你能举例说明 a 的使用吗非登录交互壳?
答案1
登录 shell 是当您登录交互式会话时在您的用户 ID 下执行的第一个进程。登录过程告诉 shell 作为登录 shell,并遵循以下约定:传递参数 0,该参数通常是 shell 可执行文件的名称,并在-
前面添加一个字符(例如-bash
,通常是bash
)。登录 shell 通常读取一个文件,该文件执行诸如设置环境变量之类的操作:/etc/profile
对于~/.profile
传统的 Bourne shell,~/.bash_profile
另外还有 bash †、zsh †和csh 等。/etc/zprofile
~/.zprofile
/etc/csh.login
~/.login
当您在文本控制台、通过 SSH 或使用 登录时su -
,您会得到一个交互式登录壳。当您以图形模式登录时(在X 显示管理器),您不会获得登录 shell,而是获得会话管理器或窗口管理器。
运行一个是很少见的非交互式登录shell,但是当您使用显示管理器登录时,某些 X 设置会执行此操作,以便安排读取配置文件。其他设置(这取决于发行版和显示管理器)明确读取/etc/profile
或~/.profile
不读取它们。获得非交互式登录 shell 的另一种方法是使用通过标准输入传递的命令远程登录,该命令不是终端,例如(与运行非交互式、非登录 shellssh example.com <my-script-which-is-stored-locally
相反)。ssh example.com my-script-which-is-on-the-remote-machine
当您在现有会话的终端(屏幕、X 终端、Emacs 终端缓冲区、另一个 shell 等)中启动 shell 时,您会得到一个交互式、非登录壳。该 shell 可能会读取 shell 配置文件(~/.bashrc
对于 bash 调用为bash
,/etc/zshrc
对于~/.zshrc
zsh/etc/csh.cshrc
和~/.cshrc
csh ,由 POSIX/XSI 兼容 shell 的变量指示的文件,ENV
例如,当调用为 时sh
,$ENV
如果设置并且~/.mkshrc
对于 mksh 等)。
当 shell 运行脚本或在其命令行上传递的命令时,它是非交互、非登录壳。这样的 shell 一直在运行:很常见的是,当一个程序调用另一个程序时,它实际上在 shell 中运行一个小脚本来调用另一个程序。在这种情况下,某些 shell 会读取启动文件(bash 运行由变量指示的文件BASH_ENV
,zsh 运行/etc/zshenv
和~/.zshenv
),但这是有风险的:shell 可以在各种上下文中调用,并且几乎没有任何可能不可以做的事情。打破一些东西。
†我稍微简化了一下,请参阅手册了解详细信息。
答案2
判断您是否处于登录 shell 中:
prompt> echo $0
-bash # "-" is the first character. Therefore, this is a login shell.
prompt> echo $0
bash # "-" is NOT the first character. This is NOT a login shell.
在 Bash 中,您还可以使用shopt login_shell
:
prompt> shopt login_shell
login_shell off
(或on
在登录 shell 中)。
信息可以在man bash
(搜索调用)中找到。以下是摘录:
登录 shell 的参数零的第一个字符是 -,或者以 --login 选项开头。
你可以自己测试一下。无论何时使用 SSH,您都在使用登录 shell。例如:
prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash
使用登录 shell 的重要性在于,其中的任何设置/home/user/.bash_profile
都会被执行。如果您有兴趣,这里有更多信息(来自man bash
)
“当 bash 作为交互式登录 shell 或带有 --login 选项的非交互式 shell 被调用时,它首先从文件 /etc/profile 中读取并执行命令(如果该文件存在)。读取该文件后,它按该顺序查找
~/.bash_profile
、~/.bash_login
、 、~/.profile
,并从第一个存在且可读的命令中读取并执行命令。 启动 shell 时可以使用 --noprofile 选项来禁止此行为。
答案3
我将详细阐述 Gilles 的精彩回答,并结合 Timothy 的检查登录 shell 类型的方法。
如果您想亲眼看看,请尝试下面的片段和场景。
检查 shell 是否是(非)交互式的
if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi
检查 shell 是否(非)登录
如果输出echo $0
以 开头-
,则它是登录 shell(echo $0
输出示例:)-bash
。否则它是非登录 shell(echo $0
输出示例:)bash
。
if echo $0 | grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;
让我们将上面的两者结合起来,一次获得两条信息:
THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
THIS_SHELL_LOGIN_TYPE='non-login';
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"
应用场景:
没有特殊选项的典型 SSH 会话
ssh [email protected]
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_LOGIN_TYPE='non-login';
ubuntu@ip-172-31-0-70:~$ if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
ubuntu@ip-172-31-0-70:~$ if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
ubuntu@ip-172-31-0-70:~$ echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"
interactive/login
运行脚本或通过新 shell 显式执行
ubuntu@ip-172-31-0-70:~$ bash -c 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'
interactive/non-login
远程运行本地脚本
ssh [email protected] < checkmy.sh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)
non-interactive/login
通过 ssh 远程运行命令
ssh [email protected] 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'
non-interactive/non-login
-t
使用switch通过 ssh 远程运行命令
当您想使用-t
switch 通过 ssh 远程运行命令时,可以显式请求交互式 shell。
ssh [email protected] -t 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'
interactive/non-login
注意:关于为什么远程运行命令的主题不是login shell
更多信息这里。
答案4
在 GUI 中的新终端中启动的 shell 将是交互式非登录 shell。例如,它会获取您的 .bashrc,但不会获取您的 .profile。