为什么在 ssh shell 中导出变量会打印导出的变量列表?

ter*_*don 17 bash ssh

考虑一下:

$ ssh localhost bash -c 'export foo=bar'
terdon@localhost's password: 
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x HOME="/home/terdon"
declare -x LOGNAME="terdon"
declare -x MAIL="/var/spool/mail/terdon"
declare -x OLDPWD
declare -x PATH="/usr/bin:/bin:/usr/sbin:/sbin"
declare -x PWD="/home/terdon"
declare -x SHELL="/bin/bash"
declare -x SHLVL="2"
declare -x SSH_CLIENT="::1 55858 22"
declare -x SSH_CONNECTION="::1 55858 ::1 22"
declare -x USER="terdon"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SESSION_ID="c5"
declare -x _="/usr/bin/bash"
Run Code Online (Sandbox Code Playgroud)

为什么在bash -c通过 ssh 运行的会话中导出变量会导致该declare -x命令列表(据我所知,当前导出的变量列表)?

在没有 的情况下运行相同的事情bash -c不会这样做:

$ ssh localhost  'export foo=bar'
terdon@localhost's password: 
$
Run Code Online (Sandbox Code Playgroud)

如果我们不这样做,也不会发生export

$ ssh localhost bash -c 'foo=bar'
terdon@localhost's password: 
$ 
Run Code Online (Sandbox Code Playgroud)

我通过从一台 Ubuntu 机器 sshing 到另一台(都运行 bash 4.3.11)和在 Arch 机器上进行了测试,如上所示(bash 版本 4.4.5)。

这里发生了什么?为什么在bash -c调用中导出变量会产生此输出?

xhi*_*nne 31

当您通过 运行命令时ssh,它会通过$SHELL使用以下-c标志调用您的命令来运行:

-c    If the -c option is present, then commands are read from 
      the first non-option argument command_string.  If there  are
      arguments  after the command_string, the first argument is 
      assigned to $0 and any remaining arguments are assigned to
      the positional parameters.  
Run Code Online (Sandbox Code Playgroud)

所以,ssh remote_host "bash -c foo"实际上会运行:

/bin/your_shell -c 'bash -c foo'
Run Code Online (Sandbox Code Playgroud)

现在,由于您正在运行的命令 ( export foo=bar) 包含空格并且没有正确引用以形成一个整体,因此export将 视为要运行的命令,其余部分保存在位置参数数组中。这意味着export运行并foo=bar作为$0. 最终结果和运行一样

/bin/your_shell -c 'bash -c export'
Run Code Online (Sandbox Code Playgroud)

正确的命令是:

ssh remote_host "bash -c 'export foo=bar'"
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 9

ssh 用空格连接参数并让远程用户的登录 shell 解释它,所以在:

ssh localhost bash -c 'export foo=bar'
Run Code Online (Sandbox Code Playgroud)

ssh 要求远程 shell 解释

bash -c export foo=bar
Run Code Online (Sandbox Code Playgroud)

命令(实际上,如果远程主机是类 Unix,它将使用the-shell,-cbash -c export foo=bar作为参数运行远程 shell )。

大多数炮弹将是命令行解释为运行bash与命令bash-cexportfoo=bar作为参数(这么办的export,同时$0包含foo=bar),而你会希望它与运行它bash-cexport foo=bar作为参数。

为此,您需要使用如下命令行:

ssh localhost "bash -c 'export foo=bar'"
Run Code Online (Sandbox Code Playgroud)

(或者:

ssh localhost bash -c \'export foo=bar\'
Run Code Online (Sandbox Code Playgroud)

对此很重要)所以:

bash -c 'export foo=bar'
Run Code Online (Sandbox Code Playgroud)

命令行被传递到远程shell。该命令行会被大多数 shell 解释为bash使用bash,-cexport foo=bar参数运行命令。请注意,使用

ssh localhost 'bash -c "export foo=bar"'
Run Code Online (Sandbox Code Playgroud)

如果远程用户的登录 shell 是rces例如 where"不是特殊的引用运算符,则将不起作用。单引号是最可移植的引用运算符(尽管它们在 shell 之间的解释方式存在一些差异,请参阅如何在不知道远程用户的登录 shell 的情况下通过 ssh 执行任意简单命令?了解更多信息)。