ssh 是否在登录 shell 中运行命令(而不是 shell 本身)?

tos*_*osh 14 shell login ssh command

根据man sshd

\n
 LOGIN PROCESS\n      When a user successfully logs in, sshd does the following:\n\n      <...>\n\n            9.   Runs user's shell or command.  All commands are run under the\n                 user's login shell as specified in the system password data\xe2\x80\x90\n                 base.\n
Run Code Online (Sandbox Code Playgroud)\n

不过,尚不清楚“在用户的登录 shell 下运行”字面意思是“登录 shell,如bash -l”?我的实验表明,不,不是:

\n
$ ssh u@h shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'\nNot login shell\n
Run Code Online (Sandbox Code Playgroud)\n

我不明白为什么会这样?它导致运行的命令无法获得通常的环境,就像登录到 shell 一样。这很麻烦。

\n

Sté*_*las 15

登录 shell在该上下文中可能意味着两种不同的含义:

\n
    \n
  1. 被定义为帐户数据库中用户的登录 shell 的 shell。

    \n

    例如:

    \n
    $ getent passwd stephane\nstephane:*:1000:1000:Stephane Chazelas:/home/stephane:/bin/zsh\n
    Run Code Online (Sandbox Code Playgroud)\n

    /bin/zsh是我的登录 shell,是我在帐户数据库中输入的第 7个字段。其他一些用户可能有/bin/tcsh、、、、.../bin/fish/bin/bash/sbin/nologin/bin/false

    \n
  2. \n
  3. 用于初始化登录会话的 shell 调用,通常由登录/sshd 完成...通过前缀 with argv[0]-某些 shell 也接受 or-l选项--login)并告诉 shell 解释一些会话初始化文件如.profile.login.zlogin

    \n
  4. \n
\n

无论如何,shinssh代表shell,并且sshdrshd之前一样,总是调用 shell 来解释客户端发送的代码(如果有)。

\n

如果你运行:

\n
ssh user@host foo    bar\n
Run Code Online (Sandbox Code Playgroud)\n

其中foobar参数被传递给sshssh用空格将它们连接起来,并将foo barshell 代码发送到服务器。

\n

服务器host将运行带有 3 个参数的登录 shelluser

\n
    \n
  1. 登录 shell 的基本名称。就我而言zsh
  2. \n
  3. -c
  4. \n
  5. 客户给出的代码:foo bar在该示例中
  6. \n
\n

shell 会将其解释为其自己的语法 \xc2\xb9 中的代码,它不会作为登录 shell 运行,并且argv[0]不以-.

\n

如果没有参数传递给客户端,就像调用它时一样:

\n
ssh user@host\n
Run Code Online (Sandbox Code Playgroud)\n

然后rlogin进入该模式(就像在未传递命令时rsh运行的模式一样rlogin ),然后使用伪 tty 并sshd仅使用一个参数 ( ) 运行用户的登录 shell argv[0]

\n
    \n
  1. -在我的例子中,登录 shell 的基本名称以 a 为前缀-zsh
  2. \n
\n

这告诉 shell 它正在作为登录 shell 运行,并且它将读取.zprofile // 。.profile.login

\n

总结一下:

\n
    \n
  • ssh host shell-code就像rsh host shell-code通过让远程用户的登录 shell 解析一些代码来远程运行命令。
  • \n
  • ssh host类似于rlogin host,并通过在虚拟终端中以登录 shell 模式启动登录 shell 来远程登录。
  • \n
\n
\n

\xc2\xb9 对于这个非常简单的,除了/bin/false/sbin/nologin当然,也许对于喜欢使用/usr/bin/python3登录 shell 的用户来说,所有 shell 都会对代码进行相同的解释,但对于更复杂的 shell,会有一些变化。另请参阅如何在不知道远程用户的登录 shell 的情况下通过 ssh 执行任意简单命令?

\n

  • @DanielKessler,请注意,在 `ssh host cmd` 中,`sshd` 运行 `bash -c cmd`,而不是作为登录 shell。登录 shell 不读取 bashrc,只读取配置文件(尽管配置文件可以获取 bashrc)。bash -c cmd 也不是交互式 shell,因此也不应该读取 bashrc,但在某些系统上,bash 在编译时配置为在 sshd 调用时读取 bashrc(交互式或非交互式),这可能就是您所看到的。 (2认同)

Gil*_*il' 14

不,SSH 仅在您登录到 shell 时调用登录 shell,而不是在运行命令时调用。这意味着如果您希望登录初始化文件运行(例如~/.profile),您需要明确执行此操作。这是一个经过深思熟虑的设计选择:在大多数登录都是在文本终端上的日子里,许多用户会在其中运行命令,.profile这些命令只有在登录交互式会话时才有意义。(现在这种情况已经不太常见了,因为大多数人都在本地登录到图形会话。)您不会想要快速ssh example.com ls(或更糟糕的是)rsync example.com:somefile .来启动 Emacs 并打开调制解调器来获取电子邮件!


SSH 中的命令是一个字符串,通过将命令行参数与中间的空格连接起来而获得。例如ssh u@h shopt -q login_shell运行命令shopt -q login_shell。它完全等同于ssh u@h 'shopt -q login_shell'、 或ssh u@h 'shopt -q' login_shell等。

SSH 将该字符串传递到用户的登录 shell。SSH 不知道任何其他 shell。服务器可能在非 Unix 系统上运行,或者在没有名为sh或 的程序的受限环境中运行bash

SSH 服务器运行用户数据库中列出的可执行文件作为用户的登录 shell,但不一定作为登录 shell。当命令行非空时,它传递一个三参数列表:

  • argv[0]是程序的基本名称,遵循通常的约定。
  • argv[1]是字符串-c
  • argv[2]是客户端传递的命令。

对于空命令行,SSH 服务器调用用户的登录 shell作为登录 shell。这意味着只有一个参数的列表:

  • argv[0]是一个短划线 ( -),后跟程序的基本名称。

ssh localhost 'cat /proc/$$/cmdline | tr \\0 \\n'例如,以下是Linux 计算机上的输出:

sh
-c
cat /proc/$$/cmdline | tr \\0 \\n
Run Code Online (Sandbox Code Playgroud)

对于登录 shell,观察起来比较困难,因为登录 shell 本身通常会运行其他程序。查看发生情况的简单方法是暂时禁用登录 shell 的初始化文件,例如通过暂时重命名~/.profile(或~/.bash_profile~/.zprofile等,具体取决于您使用的 shell)。/bin/sh以下是使用帐户作为登录 shell 的示例:

$ mv ~/.profile ~/not.profile
$ ssh localhost
(/etc/motd content goes here)
Last login: Mon Apr 24 18:00:30 2023
$ cat /proc/$$/cmdline; echo
-sh
$ exit
Connection to localhost closed.
$ mv ~/not.profile ~/.profile
Run Code Online (Sandbox Code Playgroud)