在远程ssh命令中传递变量


99

我希望能够使用ssh从我的机器上运行命令并传递环境变量 $BUILD_NUMBER

这是我正在尝试的:

ssh pvt@192.168.1.133 '~/tools/myScript.pl $BUILD_NUMBER'

$BUILD_NUMBER 是在进行ssh调用的计算机上设置的,并且由于该变量在远程主机上不存在,因此不会被提取。

如何传递的值$BUILD_NUMBER


1
与Hudson无关,已删除标签。(哈德森只是创建了变量)
彼得·舒茨

Answers:


188

如果您使用

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

代替

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

您的外壳程序将$BUILD_NUMBER在将命令字符串发送到远程主机之前进行插值。


8
如果某人必须使用单引号,以使引号中包含的命令不被本地评估,则他们应使用“'$ VARIABLE'”。示例:ssh pvt@192.168.1.133'〜/ tools / run_pvt.pl“'$ BUILD_NUMBER'”'
dr.doom

3
不知道bash对单引号和双引号的反应不同。谢谢!
silgon

1
linux核心开发人员必须
沉醉

@goldstar,请注意,shell中单引号和双引号行为之间的差异比Linux早了几十年。
sarnold '19

3
PSA:如果您的字符串包含用户输入,这是一个非常糟糕的主意,并且可能使您容易遭受代码注入攻击。
Brian McCutchon '19

27

不评估单引号中的变量。使用双引号:

ssh pvt@192.168.1.133 "~/tools/run_pvt.pl $BUILD_NUMBER"

Shell将用双引号而不是单引号扩展变量。在传递给ssh命令之前,它将更改为所需的字符串。


2

(据我所知,这个答案似乎不必要地复杂,但是就空格和特殊字符而言,它很容易扩展和增强。)

您可以直接通过ssh命令的标准输入以及read从远程位置输入数据。

在以下示例中,

  1. (为方便起见)索引数组中填充了要在远程获取其值的变量的名称。
  2. 对于这些变量中的每一个,我们给出ssh一个以空值结尾的行,该行给出了变量的名称和值。
  3. shh命令本身中,我们遍历这些行以初始化所需的变量。
# Initialize examples of variables.
# The first one even contains whitespace and a newline.
readonly FOO=$'apjlljs ailsi \n ajlls\t éjij'
readonly BAR=ygnàgyààynygbjrbjrb

# Make a list of what you want to pass through SSH.
# (The “unset” is just in case someone exported
# an associative array with this name.)
unset -v VAR_NAMES
readonly VAR_NAMES=(
    FOO
    BAR
)

for name in "${VAR_NAMES[@]}"
do
    printf '%s %s\0' "$name" "${!name}"
done | ssh user@somehost.com '
    while read -rd '"''"' name value
    do
        export "$name"="$value"
    done

    # Check
    printf "FOO = [%q]; BAR = [%q]\n" "$FOO" "$BAR"
'

输出:

FOO = [$'apjlljs ailsi \n ajlls\t éjij']; BAR = [ygnàgyààynygbjrbjrb]

如果您不需要export这些,则应该可以使用declare代替export

一个真正简化的版本(如果您不需要扩展性,只需处理一个变量,等等)将如下所示:

$ ssh user@somehost.com 'read foo' <<< "$foo"

2

默认情况下,SSHD上可接受的环境变量列表包括LC_*。从而:

LC_MY_BUILDN="1.2.3" ssh -o "SendEnv LC_MY_BUILDN" ssh-host 'echo $LC_MY_BUILDN'
1.2.3

0

如前所述,您无需在远程主机上设置环境变量。相反,您可以仅在本地主机上进行元扩展,然后将值传递给远程主机。

ssh pvt@192.168.1.133 '~/tools/run_pvt.pl $BUILD_NUMBER'

如果您确实想在远程主机上设置环境变量并使用它,则可以使用该env程序

ssh pvt@192.168.1.133 "env BUILD_NUMBER=$BUILD_NUMBER ~/tools/run_pvt.pl \$BUILD_NUMBER"

在这种情况下,这有点过头了,请注意

  • env BUILD_NUMBER=$BUILD_NUMBER 在本地主机上进行元扩展
  • 远程BUILD_NUMBER环境变量将由
    远程外壳使用

0

也可以通过ssh显式传递环境变量。它确实需要通过一些服务器端设置,因此这不是一个通用的答案。

就我而言,我想将备份存储库加密密钥传递给备份存储服务器上的命令,而不必将该密钥存储在其中,但是请注意,任何环境变量在中都是可见的ps!在stdin上传递密钥的解决方案也可以,但是我发现它太麻烦了。无论如何,这是通过ssh传递环境变量的方法:

在服务器上,sshd_config通常,编辑文件/etc/ssh/sshd_config并添加AcceptEnv与要传递的变量匹配的指令。请参阅man sshd_config。就我而言,我想将变量传递给borg备份,因此我选择了:

AcceptEnv BORG_*

现在,在客户端上,使用该-o SendEnv选项发送环境变量。以下命令行设置了环境变量BORG_SECRET,然后标记了该变量以将其发送到客户端计算机(称为backup)。然后在printenv此处运行并过滤BORG变量的输出:

$ BORG_SECRET=magic-happens ssh -o SendEnv=BORG_SECRET backup printenv | egrep BORG
BORG_SECRET=magic-happens

您可以使用默认的服务器端设置“走私”变量,请参见我的答案。要点是,默认的OpenSSHd配置包含LC_*允许发送的变量,因此只需使用$LC_TvE_foo$LC_BORG_SECRET,只需确保您不会与内置变量“冲突”即可。
亚历克斯·斯特吉斯

-2

转义变量以访问ssh会话之外的变量:ssh pvt@192.168.1.133“〜/ tools / myScript.pl \ $ BUILD_NUMBER”


2
这不能实现问题的要求。
帕特里克·特伦

2
从shell的角度来看,'$FOO'等效于"\$FOO"。问题是“如何通过SSH传递shell变量?”。如@PatrickTrentin所说,这不是正确的答案,因为这样BUILD_NUMBER就不会远程设置环境变量。
吉尔斯·古瓦拉戴特
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.