我了解交互式 shell 和非交互式 shell 之间的基本区别。但是,登录 shell 与非登录 shell 的确切区别是什么?
你能举例说明非登录交互式shell 的使用吗?
Gil*_*il' 409
当您登录交互式会话时,登录 shell 是在您的用户 ID 下执行的第一个进程。登录过程告诉 shell 作为一个登录 shell 使用一个约定:传递参数 0,它通常是 shell 可执行文件的名称,-前面带有一个字符(例如-bash,通常是bash。登录 shell 通常读取一个文件之类的设置环境变量:/etc/profile和~/.profile为传统Bourne shell的,~/.bash_profile另外对于bash †,/etc/zprofile并~/.zprofile为zsh的†,/etc/csh.login并~/.login为CSH等。
当您在文本控制台或通过 SSH 或使用登录时su -,您将获得一个交互式登录shell。当您以图形模式(在X 显示管理器上)登录时,您不会获得登录外壳,而是获得会话管理器或窗口管理器。
很少运行非交互式登录shell,但是当您使用显示管理器登录时,某些 X 设置会这样做,以便安排读取配置文件。其它设置(这取决于上的分布和显示管理器)中读取/etc/profile和~/.profile明确的,或者不读它们。获得非交互式登录 shell 的另一种方法是使用通过标准输入传递的命令远程登录,该命令不是终端,例如ssh example.com <my-script-which-is-stored-locally(与ssh example.com my-script-which-is-on-the-remote-machine运行非交互式、非登录 shell 的 相比)。
当您在现有会话(屏幕、X 终端、Emacs 终端缓冲区、另一个内部的 shell 等)的终端中启动 shell 时,您将获得一个交互式的非登录shell。该外壳可能会读出壳配置文件(~/.bashrc对于bash援引为bash,/etc/zshrc和~/.zshrc用于zsh的,/etc/csh.cshrc和~/.cshrc用于CSH,该文件通过指定ENV对POSIX / XSI兼容外壳,例如仪表板,KSH,和bash可变时作为调用sh,$ENV如果设置和~/.mkshrc对于 mksh 等)。
当 shell 运行脚本或在其命令行上传递的命令时,它是一个非交互式、非登录的shell。这样的 shell 一直运行:当一个程序调用另一个程序时,它实际上在 shell 中运行一个小脚本来调用另一个程序是很常见的。在这种情况下,一些 shell 读取启动文件(bash 运行由BASH_ENV变量指示的文件,zsh 运行/etc/zshenv和~/.zshenv),但这是有风险的:shell 可以在各种上下文中调用,几乎没有任何你可以做的事情打破东西。
†我正在简化一点,有关血腥的详细信息,请参阅手册。
Tim*_*iam 69
要判断您是否在登录 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.
Run Code Online (Sandbox Code Playgroud)
在 Bash 中,您还可以使用shopt login_shell:
prompt> shopt login_shell
login_shell off
Run Code Online (Sandbox Code Playgroud)
(或on在登录外壳中)。
信息可以在man bash(搜索调用)中找到。这是摘录:
登录 shell 是参数零的第一个字符是 - 或以 --login 选项开头的 shell。
你可以自己测试一下。无论何时您使用 SSH,您都在使用登录 shell。例如:
prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash
Run Code Online (Sandbox Code Playgroud)
使用登录 shell 的重要性在于,任何设置都/home/user/.bash_profile将被执行。如果您有兴趣,这里有更多信息(来自man bash)
“当 bash 作为交互式登录 shell 或作为带有 --login 选项的非交互式 shell 调用时,它首先从文件 /etc/profile 中读取并执行命令(如果该文件存在)。读取该文件后,它以该顺序查找
~/.bash_profile,~/.bash_login, 和~/.profile, 并从第一个存在且可读的命令中读取和执行命令。启动 shell 时可以使用 --noprofile 选项来禁止这种行为。”
小智 24
在登录 shell 中,argv[0][0] == '-'. 这就是它如何知道它是一个登录shell。
然后在某些情况下,它的行为取决于其“登录外壳”状态。例如,不是登录shell 的shell 不会执行“注销”命令。
小智 14
我将详细说明 Gilles 的出色回答,并结合 Timothy 的检查登录 shell 类型的方法。
如果您喜欢亲自查看事物,请尝试下面的片段和场景。
检查 shell 是否是(非)交互式的
if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi
Run Code Online (Sandbox Code Playgroud)
检查 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;
Run Code Online (Sandbox Code Playgroud)
让我们将以上两者结合起来,同时获取两条信息:
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"
Run Code Online (Sandbox Code Playgroud)
ssh ubuntu@34.247.105.87
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
ssh ubuntu@34.247.105.87 < 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
Run Code Online (Sandbox Code Playgroud)
ssh ubuntu@34.247.105.87 '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
Run Code Online (Sandbox Code Playgroud)
-tswitch通过 ssh 远程运行命令当您想使用-tswitch通过 ssh 远程运行命令时,您可以明确请求交互式 shell 。
ssh ubuntu@34.247.105.87 -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
Run Code Online (Sandbox Code Playgroud)
注意:关于为什么远程运行命令不是这里的login shell更多信息。
小智 6
这是旧线程,但我刚刚找到了非登录交互式 shell 的具体示例。
当我在 Linux VM 上使用 VSCode 进行远程开发时,我意识到/etc/profile.d/env_file.sh即使重新启动 VSCode 和终端本身,VSCode 集成终端也没有获取我的环境变量。输出$0表明它不是登录 shell。
看起来,在连接到远程 Linux 计算机后,VSCode 只是启动了一个主登录 shell,但对于每个集成终端,它只是启动了另一个/bin/bash进程。ps您会看到does not have a的输出-,但这并不能决定当前 shell 是否登录。
$ echo $0
/bin/bash
$ ps $$
PID TTY STAT TIME COMMAND
2274 pts/3 Ss 0:00 /bin/bash
Run Code Online (Sandbox Code Playgroud)
当我直接通过 SSH 登录服务器时,我看到-bash,这是一个登录 shell。
~$ echo $0
-bash
~$ ps $$
PID TTY STAT TIME COMMAND
2088 pts/2 Ss 0:00 -bash
Run Code Online (Sandbox Code Playgroud)
然后我-l在 VSCode 中添加了 shell 参数 ( ) 选项。现在,echo 的输出$0是相同的,但请注意$$(当前进程的 ID,PID)/bin/bash带有-l( --login) 选项。
$ echo $0
/bin/bash
$ ps $$
PID TTY STAT TIME COMMAND
2309 pts/3 Ss 0:00 /bin/bash -l
Run Code Online (Sandbox Code Playgroud)
因此,要检查 shell 是否是登录 shell,您需要检查echo $0和ps $$。根据实现,输出应该是-bash或者/bin/bash -l
吉尔斯的回答很好,但对我来说很难理解,所以这是我个人需要用更简单的语言了解的要点。
登录shell是用户登录时提供给用户的 shell。所以用户登录后只会存在其中之一。
非登录 shell是在不受登录过程干扰的情况下调用的 shell。非登录 shell 不需要每次登录都有一个,因此登录后您可能会获得任意数量的非登录 shell。
两者之间的区别允许用户将每次登录只需要执行一次的任务(例如一些繁重的任务)绑定到登录 shell 的启动,并避免在创建每个新的非登录时触发它们shell(他们可能需要很多个)。通过下面的两个例子,事情会变得更加清晰(希望如此)。
示例1:
首先创建一个新用户(之后不要切换到它):
sudo adduser foo
Run Code Online (Sandbox Code Playgroud)
然后成为根:
sudo -i
Run Code Online (Sandbox Code Playgroud)
并将此行添加到/home/foo/.profile:
echo "Echoed on start of $USER's login shell"
Run Code Online (Sandbox Code Playgroud)
现在使用 su 切换新用户,如下所示(猜猜首先会发生什么):
su foo
Run Code Online (Sandbox Code Playgroud)
你不会看到任何回声。你可能期望你添加到文件中的echo/home/foo/.profile能够运行,因为这个文件是一个登录触发的文件,但问题不在于这个文件,问题在于你根本没有登录过foo(是的,虽然它提示了你输入 foo 的密码)。因此,尽管您可以使用该命令切换到其他用户su <username>,但这根本不是“登录”。只是切换后,每当你运行命令时,都会使用该用户的ID和组ID,而不是你的。即根据man su:
su 允许使用替代用户和组 ID 运行命令。
那么,当切换到某个用户时,我们如何登录该用户(并获取该用户的登录 shell)呢?我们在 中读到man su我们可以使用其中一个选项-, -l, --login!
-、-l、--login:将 shell 作为登录 shell 启动...
因此,此时如果您exit,您将不会退出“foo”,您将退出您自己的用户!因此exit,我们不再使用 ing,而是再次使用以下命令切换回我们自己的用户su:
su <your_own_user_name>
Run Code Online (Sandbox Code Playgroud)
现在运行这个命令:
su --login foo
Run Code Online (Sandbox Code Playgroud)
并给出 foo 的密码。这次,您将看到这一行回显:
在 foo 的登录 shell 启动时回显
现在您也可以运行exit,注销 foo 并切换到您自己的登录 shell。
示例2:
将此行添加到您的~/.profile:
echo "start of $USER's login shell"
Run Code Online (Sandbox Code Playgroud)
保存,然后打开一个新终端,你会看到它回显。现在运行:
echo $0
Run Code Online (Sandbox Code Playgroud)
您必须看到(假设您使用的是 Bash):
-bash
Run Code Online (Sandbox Code Playgroud)
如您所见,它是 shell 程序的名称,前面带有破折号,这意味着它是登录 shell。现在运行:
bash
Run Code Online (Sandbox Code Playgroud)
您不会看到任何回显,但从现在开始,您将不再处于以前的 Bash 中,您只是收到了一个新的非登录 bash shell。确认:
echo $0
Run Code Online (Sandbox Code Playgroud)
现在它不能再以破折号开头,即:
bash
Run Code Online (Sandbox Code Playgroud)
您可能想在哪里使用它?例如,当您需要通过将某些命令作为“参数”传递给 bash 来运行它们时。一个著名的例子是在命令后面使用“sudo”,该命令重定向到需要 sudo 权限的文件:
sudo echo 'example line' >> /path/to/file/requiring/sudo/privileges
Run Code Online (Sandbox Code Playgroud)
尽管 sudo 将以 root 身份运行该命令,但重定向仍然会提前执行(打开文件并准备重定向),因此会打印一个漂亮的“权限错误”,整个命令将失败。相反,您可以使用非登录 shell 作为 root,并将整个命令作为单个参数传递给它。例如:
sudo bash -c "echo 'example line' >> /path/to/file/requiring/sudo/privileges"
Run Code Online (Sandbox Code Playgroud)
当然,您不希望每次执行此类命令时都会触发 root 的启动文件!
| 归档时间: |
|
| 查看次数: |
246279 次 |
| 最近记录: |