考虑一下:
$ 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
,-c
和bash -c export foo=bar
作为参数运行远程 shell)。
大多数 shell 会将该命令行解释为bash
以bash
、-c
和export
作为foo=bar
参数运行命令(因此在包含export
时运行),而您希望它以、和作为参数运行。$0
foo=bar
bash
-c
export 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
-c
export foo=bar
ssh localhost 'bash -c "export foo=bar"'
rc
如果远程用户的登录 shell 是或者es
例如 where"
不是特殊的引用运算符,则该操作将不起作用。单引号是最可移植的引用运算符(尽管它们在 shell 之间的解释方式存在一些差异,请参阅如何在不知道远程用户的登录 shell 的情况下通过 ssh 执行任意简单命令?了解更多信息)。