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

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

考虑一下:

$ 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"

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

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

$ ssh localhost  'export foo=bar'
terdon@localhost's password: 
$

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

$ ssh localhost bash -c 'foo=bar'
terdon@localhost's password: 
$ 

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

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

答案1

当您通过 运行命令时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.  

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

/bin/your_shell -c 'bash -c foo'

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

/bin/your_shell -c 'bash -c export'

正确的命令是:

ssh remote_host "bash -c 'export foo=bar'"

答案2

ssh将参数与空格连接起来,并让远程用户的登录 shell 对其进行解释,因此:

ssh localhost bash -c 'export foo=bar'

ssh要求远程 shell 解释

bash -c export foo=bar

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

大多数 shell 会将该命令行解释为bashbash-cexport作为foo=bar参数运行命令(因此在包含export时运行),而您希望它以、和作为参数运行。$0foo=barbash-cexport foo=bar

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

ssh localhost "bash -c 'export foo=bar'"

(或者:

ssh localhost bash -c \'export foo=bar\'

对于这一点)所以:

bash -c 'export foo=bar'

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

ssh localhost 'bash -c "export foo=bar"'

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

相关内容