Linux 通过 SSH 将变量传递给远程脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6746168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:08:27  来源:igfitidea点击:

Pass variables to remote script through SSH

linuxbashshellubuntussh

提问by Max

I am running scripts on a remote server from a local server via SSH. The script gets copied over using SCP in a first place, then called while being passed some arguments as follows:

我正在通过 SSH 从本地服务器在远程服务器上运行脚本。首先使用 SCP 复制脚本,然后在传递一些参数时调用,如下所示:

scp /path/to/script server.example.org:/another/path/

ssh server.example.org \
MYVAR1=1 \
MYVAR2=2 \
/another/path/script

This works fine and on the remote server, the variables MYVAR1and MYVAR2are available with their corresponding value.

这工作正常,并且在远程服务器上,变量MYVAR1MYVAR2可以使用其相应的值。

The issue is that these scripts are in constant development which requires the SSH command to be changed every-time a variable is renamed, added, or removed.

问题是这些脚本在不断开发中,每次重命名、添加或删除变量时都需要更改 SSH 命令。

I'm looking for a way of passing all the local environment variables to the remote script (since MYVAR1and MYVAR2are actually local environment variables) which would address the SSH command maintenance issue.

我正在寻找一种将所有本地环境变量传递给远程脚本的方法(因为MYVAR1并且MYVAR2实际上是本地环境变量),这将解决 SSH 命令维护问题。

Since MYVAR1=1 \and MYVAR1=1 \are lines which follow the envcommand output I tried replacing them with the actual command as follows:

由于MYVAR1=1 \MYVAR1=1 \是跟随env命令输出的行,我尝试用实际命令替换它们,如下所示:

ssh server.example.org \
`env`
/another/path/script

This seems to work for "simple" envoutput lines (e.g. SHELL=/bin/bashor LOGNAME=sysadmin), however I get errors for more "complex" output lines (e.g. LS_COLORS=rs=0:di=01;34:ln=01;[...]which gives errors such as -bash: 34:ln=01: command not found). I can get rid of these errors by unsetting the variables corresponding to those complex output lines before running the SSH command (e.g. unset LS_COLORS, then ssh [...]) however I don't find this very solution very reliable.

这似乎适用于“简单”env输出行(例如SHELL=/bin/bashLOGNAME=sysadmin),但是我会收到更“复杂”输出行的LS_COLORS=rs=0:di=01;34:ln=01;[...]错误(例如,会出现错误,例如-bash: 34:ln=01: command not found)。我可以通过在运行 SSH 命令(例如unset LS_COLORS, then ssh [...])之前取消设置与那些复杂输出行对应的变量来消除这些错误,但是我认为这个解决方案不是很可靠。

Q: Does anybody know how to pass all the local environment variables to a remote script via SSH?

问:有谁知道如何通过 SSH 将所有本地环境变量传递给远程脚本?

PS: the local environment variables are not environment variables available on the remote machine so I cannot use this solution.

PS:本地环境变量不是远程机器上可用的环境变量,所以我不能使用这个解决方案

Update with solution

更新解决方案

I ended using sedto format the envcommand output from VAR=VALUEto VAR="VALUE"(and concatenating all lines in to 1) which prevents bash from interpreting some of the output as commands and fixes my problem.

我结束使用sed的格式化env命令输出VAR=VALUEVAR="VALUE"(和连接到1中的所有行),其防止从解释一些的输出作为命令和修复我的问题的抨击。

ssh server.example.org \
`env | sed 's/\([^=]*\)=\(.*\)/=""/' | tr '\n' ' '` \
"/another/path/script"

采纳答案by carlpett

I happened to read the sshd_configman page unrelated to this and found the option AcceptEnv:

我碰巧阅读了sshd_config与此无关的手册页并找到了选项AcceptEnv

AcceptEnvSpecifies what environment variables sent by the client will be copied into the session's environ(7). See SendEnv in ssh_config(5) for how to configure the client. Note that envi- ronment passing is only supported for protocol 2. Variables are specified by name, which may contain the wildcard characters *' and?'. Multiple environment variables may be separated by whitespace or spread across multiple AcceptEnv directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be taken in the use of this directive. The default is not to accept any environment variables.

AcceptEnv指定客户端发送的哪些环境变量将被复制到会话的环境 (7) 中。有关如何配置客户端,请参阅 ssh_config(5) 中的 SendEnv。请注意,仅协议 2 支持环境传递。变量由名称指定,其中可能包含通配符*' and?'。多个环境变量可以用空格分隔或分布在多个 AcceptEnv 指令中。请注意,某些环境变量可用于绕过受限制的用户环境。因此,在使用该指令时应格外小心。默认是不接受任何环境变量。

Maybe you could use this with AcceptEnv: *? I haven't got a box with sshd handy, but try it out!

也许你可以用这个AcceptEnv: *?我手边没有带 sshd 的盒子,但请尝试一下!

回答by Lynch

The problem is that ;mark the end of your command. You must escape them:

问题是;标记命令的结束。你必须逃避他们:

Try whit this command:

试试这个命令:

env | sed 's/;/\;/g'

Update: I tested the command whit a remote host and it worked for me using this command:

更新:我在远程主机上测试了该命令,它使用以下命令对我有用:

var1='something;using semicolons;'
ssh hostname "`env | sed 's/;/\\;/g' | sed 's/.*/set &\;/g'` echo \"$var1\""

I double escape ;whit \\\\;and then I use an other sed substitution to output variables in the form of set name=value;. Doing this ensure every variables get setted correclty on the remote host before executing the command.

我对;whit 进行双重转义\\\\;,然后使用其他 sed 替换以set name=value;. 这样做可以确保在执行命令之前在远程主机上正确设置每个变量。

回答by carlpett

How about uploading the environment at the same time?

同时上传环境怎么样?

scp /path/to/script server.example.org:/another/path/
env > environment
scp environment server.example.org:/another/path
ssh server.example.org "source environment; /another/path/script"

回答by salva

Perl to the rescue:

Perl 来拯救:

#!/usr/bin/perl

use strict;
use warnings;

use Net::OpenSSH;
use Getopt::Long;

my $usage = "Usage:\n  
scp /path/to/script server.example.org:/another/path/
set > environment
scp environment server.example.org:/another/path/
ssh server.example.org "source environment; /another/path/script"
--env=FOO --env=BAR ... [user\@]host command args\n\n"; my @envs; GetOptions("env=s" => \@envs) or die $usage; my $host = shift @ARGV; die $usage unless defined $host and @ARGV; my $ssh = Net::OpenSSH->new($host); $ssh->error and die "Unable to connect to remote host: " . $ssh->error; my @cmds; for my $env (@envs) { next unless defined $ENV{$env}; push @cmds, "export " . $ssh->shell_quote($env) .'='.$ssh->shell_quote($ENV{$env}) } my $cmd = join('&&', @cmds, '('. join(' ', @ARGV) .')'); warn "remote command: $cmd\n"; $ssh->system($cmd);

And it will not break in case your environment variables contain funny things as quotes.

如果您的环境变量包含有趣的东西作为引号,它也不会中断。

回答by David Newcomb

You should use setinstead of env.

您应该使用set而不是env.

From the bash manual:

从 bash 手册:

Without options, the name and value of each shell variable are displayed in a format that can be reused as input for setting or resetting the currently-set variables.

如果没有选项,每个 shell 变量的名称和值将以一种格式显示,该格式可以重复用作设置或重置当前设置的变量的输入。

This will take care of all your semi-colon and backslash issues.

这将处理您所有的分号和反斜杠问题。

set | grep -v "DONT_NEED" > environment

If there are any variables you don't want to send over you can filter them out with something like:

如果有任何您不想发送的变量,您可以使用以下内容过滤掉它们:

ssh server.example.org "/another/path/script"

You could also update the ~/.bash_profileon the remote system to run the environment script as you log in so you wouldn't have to run the environment script explicit:

您还可以更新~/.bash_profile远程系统上的 以在登录时运行环境脚本,这样您就不必显式运行环境脚本:

#!/bin/sh
echo "local"
echo ""
echo ""
/usr/bin/ssh [email protected] "/path/test.sh \"\" \"\";"

回答by ppo

This solution works well for me. Suppose you have script which takes two params or have two variables:

这个解决方案对我很有效。假设您有一个带有两个参数或两个变量的脚本:

#!/bin/bash
echo "remote"
echo ""
echo ""

And script test.sh on 192.168.1.2:

并在 192.168.1.2 上编写 test.sh 脚本:

local
This is first params
And this is second
remote
This is first params
And this is second

Output will be:

输出将是:

##代码##