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


17

考虑一下:

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

为什么在bash -c通过ssh运行的会话中导出变量会导致该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计算机上进行测试,如上所示(自bash版本4.4.5)向其自身旋转。

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


这不能回答问题,但是输出是running的结果export。Zsh做同样的事情。
斯蒂芬·基特

@StephenKitt是的,我知道是export,我正在尝试了解正在发生的事情。我将进行编辑以澄清这仅在导出时发生。
terdon

好的,我将阅读“据我所知,当前导出的变量的列表”,这意味着您不知道输出来自何处。
斯蒂芬·基特

@StephenKitt我的意思是我不确定这是每个导出的变量还是特定的子集或什么。哦! 您是说它是export单独运行的结果?我不明白。
terdon

请注意,foo=bar它不会出现在列表中。
deltab

Answers:


31

当您通过运行命令时,通过使用标记ssh调用your 来运行该命令:$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'"

9

ssh 将参数用空格连接起来,并让远程用户的登录shell解释它,因此在:

ssh localhost bash -c 'export foo=bar'

ssh 正在要求远程外壳解释

bash -c export foo=bar

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

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

为此,您需要使用类似以下的命令行:

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

(要么:

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

因此):

bash -c 'export foo=bar'

命令行被传递到远程外壳。大多数外壳程序会将命令行解释为bash使用bash-cexport foo=bar参数运行命令。注意使用

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

是行不通的,如果远程用户的登录shell是rces为实例,其中"是不是一个特殊的引用运营商。单引号是最可移植的引号运算符(尽管在shell之间如何解释它们有一些差异,有关更多信息,请参见如何在ssh上执行任意简单命令而又不知道远程用户的登录shell?)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.